@visual-json/react 0.1.1 → 0.2.0
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/README.md +0 -4
- package/dist/index.d.mts +11 -7
- package/dist/index.d.ts +11 -7
- package/dist/index.js +630 -667
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +626 -669
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
- package/LICENSE +0 -201
package/dist/index.mjs
CHANGED
|
@@ -33,6 +33,91 @@ function useStudio() {
|
|
|
33
33
|
return ctx;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// src/get-visible-nodes.ts
|
|
37
|
+
function getVisibleNodes(root, isExpanded) {
|
|
38
|
+
const result = [];
|
|
39
|
+
function walk(node) {
|
|
40
|
+
result.push(node);
|
|
41
|
+
if (isExpanded(node.id) && (node.type === "object" || node.type === "array")) {
|
|
42
|
+
for (const child of node.children) {
|
|
43
|
+
walk(child);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
walk(root);
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/selection-utils.ts
|
|
52
|
+
import { removeNode } from "@visual-json/core";
|
|
53
|
+
function computeSelectAllIds(tree, focusedNodeId, currentlySelected) {
|
|
54
|
+
if (!focusedNodeId) return null;
|
|
55
|
+
let node = tree.nodesById.get(focusedNodeId);
|
|
56
|
+
if (!node) return null;
|
|
57
|
+
while (node) {
|
|
58
|
+
const parent = node.parentId ? tree.nodesById.get(node.parentId) : void 0;
|
|
59
|
+
const siblings = parent ? parent.children : [tree.root];
|
|
60
|
+
const siblingIds = new Set(siblings.map((s) => s.id));
|
|
61
|
+
const allSelected = siblings.every((s) => currentlySelected.has(s.id));
|
|
62
|
+
if (!allSelected) {
|
|
63
|
+
return siblingIds;
|
|
64
|
+
}
|
|
65
|
+
if (!parent || !parent.parentId) return siblingIds;
|
|
66
|
+
node = parent;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
function computeRangeIds(visibleNodes, anchorId, targetId) {
|
|
71
|
+
const anchorIdx = visibleNodes.findIndex((n) => n.id === anchorId);
|
|
72
|
+
const targetIdx = visibleNodes.findIndex((n) => n.id === targetId);
|
|
73
|
+
if (anchorIdx === -1 || targetIdx === -1) return null;
|
|
74
|
+
const start = Math.min(anchorIdx, targetIdx);
|
|
75
|
+
const end = Math.max(anchorIdx, targetIdx);
|
|
76
|
+
const ids = /* @__PURE__ */ new Set();
|
|
77
|
+
for (let i = start; i <= end; i++) {
|
|
78
|
+
ids.add(visibleNodes[i].id);
|
|
79
|
+
}
|
|
80
|
+
return ids;
|
|
81
|
+
}
|
|
82
|
+
function deleteSelectedNodes(tree, selectedIds, visibleNodes) {
|
|
83
|
+
const idsToDelete = [...selectedIds].filter((id) => {
|
|
84
|
+
const node = tree.nodesById.get(id);
|
|
85
|
+
if (!node || node.parentId === null) return false;
|
|
86
|
+
let cur = tree.nodesById.get(node.parentId);
|
|
87
|
+
while (cur) {
|
|
88
|
+
if (selectedIds.has(cur.id)) return false;
|
|
89
|
+
cur = cur.parentId ? tree.nodesById.get(cur.parentId) : void 0;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
});
|
|
93
|
+
if (idsToDelete.length === 0) return { newTree: tree, nextFocusId: null };
|
|
94
|
+
const firstDeletedIdx = visibleNodes.findIndex((n) => selectedIds.has(n.id));
|
|
95
|
+
let newTree = tree;
|
|
96
|
+
for (const id of idsToDelete) {
|
|
97
|
+
if (newTree.nodesById.has(id)) {
|
|
98
|
+
newTree = removeNode(newTree, id);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
let nextFocusId = null;
|
|
102
|
+
for (let i = firstDeletedIdx; i < visibleNodes.length; i++) {
|
|
103
|
+
const id = visibleNodes[i].id;
|
|
104
|
+
if (!selectedIds.has(id) && newTree.nodesById.has(id)) {
|
|
105
|
+
nextFocusId = id;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!nextFocusId) {
|
|
110
|
+
for (let i = firstDeletedIdx - 1; i >= 0; i--) {
|
|
111
|
+
const id = visibleNodes[i].id;
|
|
112
|
+
if (!selectedIds.has(id) && newTree.nodesById.has(id)) {
|
|
113
|
+
nextFocusId = id;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { newTree, nextFocusId };
|
|
119
|
+
}
|
|
120
|
+
|
|
36
121
|
// src/visual-json.tsx
|
|
37
122
|
import { jsx } from "react/jsx-runtime";
|
|
38
123
|
function collectAllIds(node) {
|
|
@@ -49,10 +134,42 @@ function VisualJson({
|
|
|
49
134
|
children
|
|
50
135
|
}) {
|
|
51
136
|
const [tree, setTreeState] = useState(() => fromJson(value));
|
|
52
|
-
const [
|
|
137
|
+
const [focusedNodeId, setFocusedNodeId] = useState(null);
|
|
138
|
+
const [selectedNodeIds, setSelectedNodeIdsState] = useState(
|
|
139
|
+
() => /* @__PURE__ */ new Set()
|
|
140
|
+
);
|
|
141
|
+
const selectedNodeIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
142
|
+
const setSelectedNodeIds = useCallback((ids) => {
|
|
143
|
+
selectedNodeIdsRef.current = ids;
|
|
144
|
+
setSelectedNodeIdsState(ids);
|
|
145
|
+
}, []);
|
|
146
|
+
const anchorNodeIdRef = useRef(null);
|
|
147
|
+
const [anchorNodeId, setAnchorNodeIdState] = useState(null);
|
|
148
|
+
const [drillDownNodeId, setDrillDownNodeId] = useState(null);
|
|
53
149
|
const [expandedNodeIds, setExpandedNodeIds] = useState(
|
|
54
150
|
() => /* @__PURE__ */ new Set([tree.root.id])
|
|
55
151
|
);
|
|
152
|
+
const setAnchorNodeId = useCallback((id) => {
|
|
153
|
+
anchorNodeIdRef.current = id;
|
|
154
|
+
setAnchorNodeIdState(id);
|
|
155
|
+
}, []);
|
|
156
|
+
const focusSelectAndDrillDown = useCallback(
|
|
157
|
+
(nodeId) => {
|
|
158
|
+
setFocusedNodeId(nodeId);
|
|
159
|
+
setSelectedNodeIds(nodeId ? /* @__PURE__ */ new Set([nodeId]) : /* @__PURE__ */ new Set());
|
|
160
|
+
setAnchorNodeId(nodeId);
|
|
161
|
+
setDrillDownNodeId(nodeId);
|
|
162
|
+
},
|
|
163
|
+
[setSelectedNodeIds, setAnchorNodeId]
|
|
164
|
+
);
|
|
165
|
+
const visibleNodes = useMemo(
|
|
166
|
+
() => getVisibleNodes(tree.root, (id) => expandedNodeIds.has(id)),
|
|
167
|
+
[tree.root, expandedNodeIds]
|
|
168
|
+
);
|
|
169
|
+
const visibleNodesOverrideRef = useRef(null);
|
|
170
|
+
const setVisibleNodesOverride = useCallback((nodes) => {
|
|
171
|
+
visibleNodesOverrideRef.current = nodes;
|
|
172
|
+
}, []);
|
|
56
173
|
const historyRef = useRef(new History());
|
|
57
174
|
const isInternalChange = useRef(false);
|
|
58
175
|
const hasMounted = useRef(false);
|
|
@@ -81,7 +198,7 @@ function VisualJson({
|
|
|
81
198
|
const newTree = fromJson(value);
|
|
82
199
|
setTreeState(newTree);
|
|
83
200
|
setExpandedNodeIds(/* @__PURE__ */ new Set([newTree.root.id]));
|
|
84
|
-
|
|
201
|
+
focusSelectAndDrillDown(null);
|
|
85
202
|
historyRef.current = new History();
|
|
86
203
|
historyRef.current.push(newTree);
|
|
87
204
|
setCanUndo(false);
|
|
@@ -139,8 +256,66 @@ function VisualJson({
|
|
|
139
256
|
document.addEventListener("keydown", handleKeyDown);
|
|
140
257
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
141
258
|
}, [undo, redo]);
|
|
142
|
-
const selectNode = useCallback(
|
|
143
|
-
|
|
259
|
+
const selectNode = useCallback(
|
|
260
|
+
(nodeId) => {
|
|
261
|
+
setFocusedNodeId(nodeId);
|
|
262
|
+
setSelectedNodeIds(nodeId ? /* @__PURE__ */ new Set([nodeId]) : /* @__PURE__ */ new Set());
|
|
263
|
+
setAnchorNodeId(nodeId);
|
|
264
|
+
},
|
|
265
|
+
[setSelectedNodeIds, setAnchorNodeId]
|
|
266
|
+
);
|
|
267
|
+
const selectAndDrillDown = focusSelectAndDrillDown;
|
|
268
|
+
const toggleNodeSelection = useCallback(
|
|
269
|
+
(nodeId) => {
|
|
270
|
+
const next = new Set(selectedNodeIdsRef.current);
|
|
271
|
+
if (next.has(nodeId)) {
|
|
272
|
+
next.delete(nodeId);
|
|
273
|
+
} else {
|
|
274
|
+
next.add(nodeId);
|
|
275
|
+
}
|
|
276
|
+
setSelectedNodeIds(next);
|
|
277
|
+
if (next.size === 0) {
|
|
278
|
+
setFocusedNodeId(null);
|
|
279
|
+
setAnchorNodeId(null);
|
|
280
|
+
} else {
|
|
281
|
+
setFocusedNodeId(nodeId);
|
|
282
|
+
setAnchorNodeId(nodeId);
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
[setSelectedNodeIds, setAnchorNodeId]
|
|
286
|
+
);
|
|
287
|
+
const selectNodeRange = useCallback(
|
|
288
|
+
(toNodeId) => {
|
|
289
|
+
const nodes = visibleNodesOverrideRef.current ?? visibleNodes;
|
|
290
|
+
const anchor = anchorNodeIdRef.current;
|
|
291
|
+
if (!anchor) {
|
|
292
|
+
setFocusedNodeId(toNodeId);
|
|
293
|
+
setSelectedNodeIds(/* @__PURE__ */ new Set([toNodeId]));
|
|
294
|
+
setAnchorNodeId(toNodeId);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const rangeIds = computeRangeIds(nodes, anchor, toNodeId);
|
|
298
|
+
if (!rangeIds) {
|
|
299
|
+
setFocusedNodeId(toNodeId);
|
|
300
|
+
setSelectedNodeIds(/* @__PURE__ */ new Set([toNodeId]));
|
|
301
|
+
setAnchorNodeId(toNodeId);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
setSelectedNodeIds(rangeIds);
|
|
305
|
+
setFocusedNodeId(toNodeId);
|
|
306
|
+
},
|
|
307
|
+
[visibleNodes, setSelectedNodeIds, setAnchorNodeId]
|
|
308
|
+
);
|
|
309
|
+
const setSelection = useCallback(
|
|
310
|
+
(focusedId, newSelectedIds, newAnchorId) => {
|
|
311
|
+
setFocusedNodeId(focusedId);
|
|
312
|
+
setSelectedNodeIds(newSelectedIds);
|
|
313
|
+
setAnchorNodeId(newAnchorId);
|
|
314
|
+
},
|
|
315
|
+
[setSelectedNodeIds, setAnchorNodeId]
|
|
316
|
+
);
|
|
317
|
+
const drillDown = useCallback((nodeId) => {
|
|
318
|
+
setDrillDownNodeId(nodeId);
|
|
144
319
|
}, []);
|
|
145
320
|
const toggleExpand = useCallback((nodeId) => {
|
|
146
321
|
setExpandedNodeIds((prev) => {
|
|
@@ -186,6 +361,7 @@ function VisualJson({
|
|
|
186
361
|
const matchIds = new Set(matches.map((m) => m.nodeId));
|
|
187
362
|
setSearchMatchNodeIds(matchIds);
|
|
188
363
|
if (matches.length > 0) {
|
|
364
|
+
const firstId = matches[0].nodeId;
|
|
189
365
|
const ancestors = getAncestorIds(
|
|
190
366
|
tree,
|
|
191
367
|
matches.map((m) => m.nodeId)
|
|
@@ -195,7 +371,7 @@ function VisualJson({
|
|
|
195
371
|
for (const id of ancestors) next.add(id);
|
|
196
372
|
return next;
|
|
197
373
|
});
|
|
198
|
-
|
|
374
|
+
focusSelectAndDrillDown(firstId);
|
|
199
375
|
}
|
|
200
376
|
},
|
|
201
377
|
[tree]
|
|
@@ -204,14 +380,14 @@ function VisualJson({
|
|
|
204
380
|
if (searchMatches.length === 0) return;
|
|
205
381
|
const nextIdx = (searchMatchIndex + 1) % searchMatches.length;
|
|
206
382
|
setSearchMatchIndex(nextIdx);
|
|
207
|
-
|
|
208
|
-
}, [searchMatches, searchMatchIndex]);
|
|
383
|
+
focusSelectAndDrillDown(searchMatches[nextIdx].nodeId);
|
|
384
|
+
}, [searchMatches, searchMatchIndex, focusSelectAndDrillDown]);
|
|
209
385
|
const prevSearchMatch = useCallback(() => {
|
|
210
386
|
if (searchMatches.length === 0) return;
|
|
211
387
|
const prevIdx = (searchMatchIndex - 1 + searchMatches.length) % searchMatches.length;
|
|
212
388
|
setSearchMatchIndex(prevIdx);
|
|
213
|
-
|
|
214
|
-
}, [searchMatches, searchMatchIndex]);
|
|
389
|
+
focusSelectAndDrillDown(searchMatches[prevIdx].nodeId);
|
|
390
|
+
}, [searchMatches, searchMatchIndex, focusSelectAndDrillDown]);
|
|
215
391
|
useEffect(() => {
|
|
216
392
|
if (!searchQuery.trim()) return;
|
|
217
393
|
const matches = searchNodes(tree, searchQuery);
|
|
@@ -224,7 +400,10 @@ function VisualJson({
|
|
|
224
400
|
const state = useMemo(
|
|
225
401
|
() => ({
|
|
226
402
|
tree,
|
|
227
|
-
|
|
403
|
+
focusedNodeId,
|
|
404
|
+
selectedNodeIds,
|
|
405
|
+
anchorNodeId,
|
|
406
|
+
drillDownNodeId,
|
|
228
407
|
expandedNodeIds,
|
|
229
408
|
schema: schema ?? null,
|
|
230
409
|
searchQuery,
|
|
@@ -234,7 +413,10 @@ function VisualJson({
|
|
|
234
413
|
}),
|
|
235
414
|
[
|
|
236
415
|
tree,
|
|
237
|
-
|
|
416
|
+
focusedNodeId,
|
|
417
|
+
selectedNodeIds,
|
|
418
|
+
anchorNodeId,
|
|
419
|
+
drillDownNodeId,
|
|
238
420
|
expandedNodeIds,
|
|
239
421
|
schema,
|
|
240
422
|
searchQuery,
|
|
@@ -247,6 +429,12 @@ function VisualJson({
|
|
|
247
429
|
() => ({
|
|
248
430
|
setTree,
|
|
249
431
|
selectNode,
|
|
432
|
+
selectAndDrillDown,
|
|
433
|
+
toggleNodeSelection,
|
|
434
|
+
selectNodeRange,
|
|
435
|
+
setSelection,
|
|
436
|
+
setVisibleNodesOverride,
|
|
437
|
+
drillDown,
|
|
250
438
|
toggleExpand,
|
|
251
439
|
expandNode,
|
|
252
440
|
collapseNode,
|
|
@@ -263,6 +451,12 @@ function VisualJson({
|
|
|
263
451
|
[
|
|
264
452
|
setTree,
|
|
265
453
|
selectNode,
|
|
454
|
+
selectAndDrillDown,
|
|
455
|
+
toggleNodeSelection,
|
|
456
|
+
selectNodeRange,
|
|
457
|
+
setSelection,
|
|
458
|
+
setVisibleNodesOverride,
|
|
459
|
+
drillDown,
|
|
266
460
|
toggleExpand,
|
|
267
461
|
expandNode,
|
|
268
462
|
collapseNode,
|
|
@@ -282,11 +476,9 @@ function VisualJson({
|
|
|
282
476
|
}
|
|
283
477
|
|
|
284
478
|
// src/tree-view.tsx
|
|
285
|
-
import { useState as useState4, useMemo as
|
|
479
|
+
import { useState as useState4, useMemo as useMemo3, useRef as useRef4, useCallback as useCallback3, useEffect as useEffect3 } from "react";
|
|
286
480
|
import {
|
|
287
|
-
removeNode,
|
|
288
|
-
getPropertySchema,
|
|
289
|
-
validateNode,
|
|
481
|
+
removeNode as removeNode3,
|
|
290
482
|
duplicateNode,
|
|
291
483
|
changeType,
|
|
292
484
|
toJson as toJson2
|
|
@@ -404,96 +596,199 @@ function getDisplayKey(node, state) {
|
|
|
404
596
|
return node.key;
|
|
405
597
|
}
|
|
406
598
|
|
|
407
|
-
// src/
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
599
|
+
// src/use-drag-drop.ts
|
|
600
|
+
import { useState as useState3, useCallback as useCallback2, useRef as useRef3, useMemo as useMemo2 } from "react";
|
|
601
|
+
import {
|
|
602
|
+
removeNode as removeNode2,
|
|
603
|
+
insertNode,
|
|
604
|
+
reorderChildrenMulti,
|
|
605
|
+
isDescendant
|
|
606
|
+
} from "@visual-json/core";
|
|
607
|
+
|
|
608
|
+
// src/theme.ts
|
|
609
|
+
var DEFAULT_CSS_VARS = {
|
|
610
|
+
"--vj-bg": "#1e1e1e",
|
|
611
|
+
"--vj-bg-panel": "#252526",
|
|
612
|
+
"--vj-bg-hover": "#2a2d2e",
|
|
613
|
+
"--vj-bg-selected": "#2a5a1e",
|
|
614
|
+
"--vj-bg-selected-muted": "#2a2d2e",
|
|
615
|
+
"--vj-bg-match": "#3a3520",
|
|
616
|
+
"--vj-bg-match-active": "#51502b",
|
|
617
|
+
"--vj-border": "#333333",
|
|
618
|
+
"--vj-border-subtle": "#2a2a2a",
|
|
619
|
+
"--vj-text": "#cccccc",
|
|
620
|
+
"--vj-text-muted": "#888888",
|
|
621
|
+
"--vj-text-dim": "#666666",
|
|
622
|
+
"--vj-text-dimmer": "#555555",
|
|
623
|
+
"--vj-string": "#ce9178",
|
|
624
|
+
"--vj-number": "#b5cea8",
|
|
625
|
+
"--vj-boolean": "#569cd6",
|
|
626
|
+
"--vj-accent": "#007acc",
|
|
627
|
+
"--vj-accent-muted": "#094771",
|
|
628
|
+
"--vj-input-bg": "#3c3c3c",
|
|
629
|
+
"--vj-input-border": "#555555",
|
|
630
|
+
"--vj-error": "#f48771",
|
|
631
|
+
"--vj-font": "monospace",
|
|
632
|
+
"--vj-input-font-size": "13px"
|
|
633
|
+
};
|
|
421
634
|
|
|
422
635
|
// src/use-drag-drop.ts
|
|
423
|
-
|
|
424
|
-
import { reorderChildren, moveNode } from "@visual-json/core";
|
|
636
|
+
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
425
637
|
var INITIAL_DRAG_STATE = {
|
|
426
|
-
|
|
638
|
+
draggedNodeIds: EMPTY_SET,
|
|
427
639
|
dropTargetNodeId: null,
|
|
428
640
|
dropPosition: null
|
|
429
641
|
};
|
|
430
|
-
function
|
|
642
|
+
function sortByTreeOrder(root, ids) {
|
|
643
|
+
const result = [];
|
|
644
|
+
function walk(node) {
|
|
645
|
+
if (ids.has(node.id)) result.push(node.id);
|
|
646
|
+
for (const child of node.children) walk(child);
|
|
647
|
+
}
|
|
648
|
+
walk(root);
|
|
649
|
+
return result;
|
|
650
|
+
}
|
|
651
|
+
function setMultiDragImage(e, count) {
|
|
652
|
+
const ghost = document.createElement("div");
|
|
653
|
+
ghost.textContent = `${count} selected`;
|
|
654
|
+
const root = document.querySelector("[data-form-container], [role='tree']");
|
|
655
|
+
const cs = root ? getComputedStyle(root) : null;
|
|
656
|
+
const bg = cs?.getPropertyValue("--vj-bg-selected").trim() || DEFAULT_CSS_VARS["--vj-bg-selected"];
|
|
657
|
+
const fg = cs?.getPropertyValue("--vj-text-selected").trim() || cs?.getPropertyValue("--vj-text").trim() || DEFAULT_CSS_VARS["--vj-text"];
|
|
658
|
+
const font = cs?.getPropertyValue("--vj-font").trim() || DEFAULT_CSS_VARS["--vj-font"];
|
|
659
|
+
ghost.style.cssText = [
|
|
660
|
+
"position:fixed",
|
|
661
|
+
"top:-1000px",
|
|
662
|
+
"left:-1000px",
|
|
663
|
+
"padding:4px 12px",
|
|
664
|
+
`background:${bg}`,
|
|
665
|
+
`color:${fg}`,
|
|
666
|
+
`font-family:${font}`,
|
|
667
|
+
"font-size:13px",
|
|
668
|
+
"border-radius:4px",
|
|
669
|
+
"white-space:nowrap",
|
|
670
|
+
"pointer-events:none"
|
|
671
|
+
].join(";");
|
|
672
|
+
document.body.appendChild(ghost);
|
|
673
|
+
e.dataTransfer.setDragImage(ghost, 0, 14);
|
|
674
|
+
requestAnimationFrame(() => ghost.remove());
|
|
675
|
+
}
|
|
676
|
+
function useDragDrop(visibleNodes, selectedNodeIds) {
|
|
431
677
|
const { state, actions } = useStudio();
|
|
432
678
|
const [dragState, setDragState] = useState3(INITIAL_DRAG_STATE);
|
|
433
679
|
const dragStateRef = useRef3(dragState);
|
|
434
680
|
dragStateRef.current = dragState;
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
681
|
+
const visibleNodeIndexMap = useMemo2(() => {
|
|
682
|
+
const map = /* @__PURE__ */ new Map();
|
|
683
|
+
visibleNodes.forEach((n, i) => map.set(n.id, i));
|
|
684
|
+
return map;
|
|
685
|
+
}, [visibleNodes]);
|
|
686
|
+
const handleDragStart = useCallback2(
|
|
687
|
+
(nodeId) => {
|
|
688
|
+
let ids;
|
|
689
|
+
if (selectedNodeIds.size > 0 && selectedNodeIds.has(nodeId)) {
|
|
690
|
+
ids = selectedNodeIds;
|
|
691
|
+
} else {
|
|
692
|
+
ids = /* @__PURE__ */ new Set([nodeId]);
|
|
693
|
+
}
|
|
694
|
+
setDragState({
|
|
695
|
+
draggedNodeIds: ids,
|
|
696
|
+
dropTargetNodeId: null,
|
|
697
|
+
dropPosition: null
|
|
698
|
+
});
|
|
699
|
+
},
|
|
700
|
+
[selectedNodeIds]
|
|
701
|
+
);
|
|
702
|
+
const rawDragOver = useCallback2(
|
|
443
703
|
(nodeId, position) => {
|
|
704
|
+
const draggedIds = dragStateRef.current.draggedNodeIds;
|
|
705
|
+
for (const draggedId of draggedIds) {
|
|
706
|
+
if (nodeId === draggedId || isDescendant(state.tree, nodeId, draggedId)) {
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
444
710
|
setDragState((prev) => ({
|
|
445
711
|
...prev,
|
|
446
712
|
dropTargetNodeId: nodeId,
|
|
447
713
|
dropPosition: position
|
|
448
714
|
}));
|
|
449
715
|
},
|
|
450
|
-
[]
|
|
716
|
+
[state.tree]
|
|
717
|
+
);
|
|
718
|
+
const handleDragOver = useCallback2(
|
|
719
|
+
(nodeId, position) => {
|
|
720
|
+
if (position === "before") {
|
|
721
|
+
const idx = visibleNodeIndexMap.get(nodeId);
|
|
722
|
+
if (idx !== void 0 && idx > 0) {
|
|
723
|
+
rawDragOver(visibleNodes[idx - 1].id, "after");
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
rawDragOver(nodeId, position);
|
|
728
|
+
},
|
|
729
|
+
[visibleNodes, visibleNodeIndexMap, rawDragOver]
|
|
451
730
|
);
|
|
452
731
|
const handleDragEnd = useCallback2(() => {
|
|
453
732
|
setDragState(INITIAL_DRAG_STATE);
|
|
454
733
|
}, []);
|
|
455
734
|
const handleDrop = useCallback2(() => {
|
|
456
|
-
const {
|
|
457
|
-
if (
|
|
458
|
-
const draggedNode = state.tree.nodesById.get(draggedNodeId);
|
|
735
|
+
const { draggedNodeIds, dropTargetNodeId, dropPosition } = dragStateRef.current;
|
|
736
|
+
if (draggedNodeIds.size === 0 || !dropTargetNodeId || !dropPosition) return;
|
|
459
737
|
const targetNode = state.tree.nodesById.get(dropTargetNodeId);
|
|
460
|
-
if (!
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
738
|
+
if (!targetNode || !targetNode.parentId) return;
|
|
739
|
+
for (const id of draggedNodeIds) {
|
|
740
|
+
if (isDescendant(state.tree, dropTargetNodeId, id)) return;
|
|
741
|
+
}
|
|
742
|
+
const targetParentId = targetNode.parentId;
|
|
743
|
+
const targetParent = state.tree.nodesById.get(targetParentId);
|
|
744
|
+
if (!targetParent) return;
|
|
745
|
+
const parentChildren = targetParent.children;
|
|
746
|
+
const orderedDragIds = parentChildren.filter((c) => draggedNodeIds.has(c.id)).map((c) => c.id);
|
|
747
|
+
const allSameParent = orderedDragIds.length === draggedNodeIds.size && [...draggedNodeIds].every((id) => {
|
|
748
|
+
const n = state.tree.nodesById.get(id);
|
|
749
|
+
return n?.parentId === targetParentId;
|
|
750
|
+
});
|
|
751
|
+
if (allSameParent) {
|
|
752
|
+
const newTree = reorderChildrenMulti(
|
|
753
|
+
state.tree,
|
|
754
|
+
targetParentId,
|
|
755
|
+
orderedDragIds,
|
|
756
|
+
dropTargetNodeId,
|
|
757
|
+
dropPosition
|
|
758
|
+
);
|
|
759
|
+
actions.setTree(newTree);
|
|
760
|
+
} else {
|
|
761
|
+
const orderedIds = sortByTreeOrder(state.tree.root, draggedNodeIds);
|
|
762
|
+
const draggedNodes = orderedIds.map((id) => state.tree.nodesById.get(id)).filter((n) => !!n && n.parentId !== null).map((n) => structuredClone(n));
|
|
763
|
+
let newTree = state.tree;
|
|
764
|
+
for (const id of [...orderedIds].reverse()) {
|
|
765
|
+
if (newTree.nodesById.has(id)) {
|
|
766
|
+
newTree = removeNode2(newTree, id);
|
|
480
767
|
}
|
|
481
768
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
769
|
+
const updatedTarget = newTree.nodesById.get(dropTargetNodeId);
|
|
770
|
+
if (!updatedTarget || !updatedTarget.parentId) {
|
|
771
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
const updatedParent = newTree.nodesById.get(updatedTarget.parentId);
|
|
775
|
+
if (!updatedParent) {
|
|
776
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
let insertIdx = updatedParent.children.findIndex(
|
|
780
|
+
(c) => c.id === dropTargetNodeId
|
|
781
|
+
);
|
|
782
|
+
if (dropPosition === "after") insertIdx++;
|
|
783
|
+
for (let i = 0; i < draggedNodes.length; i++) {
|
|
784
|
+
newTree = insertNode(
|
|
785
|
+
newTree,
|
|
786
|
+
updatedParent.id,
|
|
787
|
+
draggedNodes[i],
|
|
788
|
+
insertIdx + i
|
|
494
789
|
);
|
|
495
|
-
actions.setTree(newTree);
|
|
496
790
|
}
|
|
791
|
+
actions.setTree(newTree);
|
|
497
792
|
}
|
|
498
793
|
setDragState(INITIAL_DRAG_STATE);
|
|
499
794
|
}, [state.tree, actions]);
|
|
@@ -515,6 +810,7 @@ function TreeNodeRow({
|
|
|
515
810
|
showValues,
|
|
516
811
|
showCounts,
|
|
517
812
|
isFocused,
|
|
813
|
+
onSelectRange,
|
|
518
814
|
onDragStart,
|
|
519
815
|
onDragOver,
|
|
520
816
|
onDragEnd,
|
|
@@ -522,19 +818,15 @@ function TreeNodeRow({
|
|
|
522
818
|
onContextMenu
|
|
523
819
|
}) {
|
|
524
820
|
const { state, actions } = useStudio();
|
|
525
|
-
const isSelected = state.
|
|
821
|
+
const isSelected = state.selectedNodeIds.has(node.id);
|
|
526
822
|
const isExpanded = state.expandedNodeIds.has(node.id);
|
|
527
823
|
const isContainer = node.type === "object" || node.type === "array";
|
|
528
824
|
const [hovered, setHovered] = useState4(false);
|
|
529
825
|
const isRoot = node.parentId === null;
|
|
530
826
|
const isSearchMatch = state.searchMatchNodeIds.has(node.id);
|
|
531
827
|
const isActiveMatch = state.searchMatches.length > 0 && state.searchMatches[state.searchMatchIndex]?.nodeId === node.id;
|
|
532
|
-
const schema = state.schema;
|
|
533
|
-
const nodeSchema = schema ? getPropertySchema(schema, node.path) : void 0;
|
|
534
|
-
const validation = nodeSchema ? validateNode(node, nodeSchema) : null;
|
|
535
|
-
const hasError = validation ? !validation.valid : false;
|
|
536
828
|
const isDragTarget = dragState.dropTargetNodeId === node.id;
|
|
537
|
-
const isDraggedNode = dragState.
|
|
829
|
+
const isDraggedNode = dragState.draggedNodeIds.has(node.id);
|
|
538
830
|
function displayValue() {
|
|
539
831
|
if (isContainer) {
|
|
540
832
|
return node.type === "array" ? `[${node.children.length}]` : `{${node.children.length}}`;
|
|
@@ -550,12 +842,12 @@ function TreeNodeRow({
|
|
|
550
842
|
const position = e.clientY < midY ? "before" : "after";
|
|
551
843
|
onDragOver(node.id, position);
|
|
552
844
|
}
|
|
553
|
-
let
|
|
554
|
-
let
|
|
845
|
+
let borderTopColor = "transparent";
|
|
846
|
+
let borderBottomColor = "transparent";
|
|
555
847
|
if (isDragTarget && dragState.dropPosition === "before") {
|
|
556
|
-
|
|
848
|
+
borderTopColor = "var(--vj-accent, #007acc)";
|
|
557
849
|
} else if (isDragTarget && dragState.dropPosition === "after") {
|
|
558
|
-
|
|
850
|
+
borderBottomColor = "var(--vj-accent, #007acc)";
|
|
559
851
|
}
|
|
560
852
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
561
853
|
/* @__PURE__ */ jsxs(
|
|
@@ -564,13 +856,24 @@ function TreeNodeRow({
|
|
|
564
856
|
role: "treeitem",
|
|
565
857
|
"aria-selected": isSelected,
|
|
566
858
|
"aria-expanded": isContainer ? isExpanded : void 0,
|
|
567
|
-
onClick: () =>
|
|
859
|
+
onClick: (e) => {
|
|
860
|
+
if (e.shiftKey) {
|
|
861
|
+
onSelectRange(node.id);
|
|
862
|
+
} else if (e.metaKey || e.ctrlKey) {
|
|
863
|
+
actions.toggleNodeSelection(node.id);
|
|
864
|
+
} else {
|
|
865
|
+
actions.selectAndDrillDown(node.id);
|
|
866
|
+
}
|
|
867
|
+
},
|
|
568
868
|
onMouseEnter: () => setHovered(true),
|
|
569
869
|
onMouseLeave: () => setHovered(false),
|
|
570
870
|
onContextMenu: (e) => onContextMenu(e, node),
|
|
571
871
|
draggable: !isRoot,
|
|
572
872
|
onDragStart: (e) => {
|
|
573
873
|
e.dataTransfer.effectAllowed = "move";
|
|
874
|
+
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
875
|
+
setMultiDragImage(e, state.selectedNodeIds.size);
|
|
876
|
+
}
|
|
574
877
|
onDragStart(node.id);
|
|
575
878
|
},
|
|
576
879
|
onDragOver: handleDragOverEvent,
|
|
@@ -584,15 +887,16 @@ function TreeNodeRow({
|
|
|
584
887
|
display: "flex",
|
|
585
888
|
alignItems: "center",
|
|
586
889
|
gap: 6,
|
|
587
|
-
padding: "
|
|
890
|
+
padding: "1px 8px",
|
|
588
891
|
paddingLeft: 8 + depth * 16,
|
|
589
892
|
cursor: "pointer",
|
|
590
893
|
backgroundColor: isSelected ? isFocused ? "var(--vj-bg-selected, #2a5a1e)" : "var(--vj-bg-selected-muted, var(--vj-bg-hover, #2a2d2e))" : isActiveMatch ? "var(--vj-bg-match-active, #51502b)" : isSearchMatch ? "var(--vj-bg-match, #3a3520)" : hovered ? "var(--vj-bg-hover, #2a2d2e)" : "transparent",
|
|
591
894
|
minHeight: 28,
|
|
592
895
|
userSelect: "none",
|
|
593
896
|
opacity: isDraggedNode ? 0.4 : 1,
|
|
594
|
-
borderTop
|
|
595
|
-
borderBottom
|
|
897
|
+
borderTop: `2px solid ${borderTopColor}`,
|
|
898
|
+
borderBottom: `2px solid ${borderBottomColor}`,
|
|
899
|
+
boxSizing: "border-box",
|
|
596
900
|
color: isSelected && isFocused ? "var(--vj-text-selected, var(--vj-text, #cccccc))" : "var(--vj-text, #cccccc)"
|
|
597
901
|
},
|
|
598
902
|
children: [
|
|
@@ -675,6 +979,7 @@ function TreeNodeRow({
|
|
|
675
979
|
showValues,
|
|
676
980
|
showCounts,
|
|
677
981
|
isFocused,
|
|
982
|
+
onSelectRange,
|
|
678
983
|
onDragStart,
|
|
679
984
|
onDragOver,
|
|
680
985
|
onDragEnd,
|
|
@@ -692,25 +997,34 @@ function TreeView({
|
|
|
692
997
|
}) {
|
|
693
998
|
const { state, actions } = useStudio();
|
|
694
999
|
const containerRef = useRef4(null);
|
|
1000
|
+
const visibleNodes = useMemo3(
|
|
1001
|
+
() => getVisibleNodes(state.tree.root, (id) => state.expandedNodeIds.has(id)),
|
|
1002
|
+
[state.tree.root, state.expandedNodeIds]
|
|
1003
|
+
);
|
|
695
1004
|
const {
|
|
696
1005
|
dragState,
|
|
697
1006
|
handleDragStart,
|
|
698
1007
|
handleDragOver,
|
|
699
1008
|
handleDragEnd,
|
|
700
1009
|
handleDrop
|
|
701
|
-
} = useDragDrop();
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
1010
|
+
} = useDragDrop(visibleNodes, state.selectedNodeIds);
|
|
1011
|
+
const handleSelectRange = useCallback3(
|
|
1012
|
+
(nodeId) => {
|
|
1013
|
+
actions.setVisibleNodesOverride(visibleNodes);
|
|
1014
|
+
actions.selectNodeRange(nodeId);
|
|
1015
|
+
},
|
|
1016
|
+
[visibleNodes, actions]
|
|
706
1017
|
);
|
|
1018
|
+
const [contextMenu, setContextMenu] = useState4(null);
|
|
707
1019
|
const handleContextMenu = useCallback3(
|
|
708
1020
|
(e, node) => {
|
|
709
1021
|
e.preventDefault();
|
|
710
|
-
|
|
1022
|
+
if (!state.selectedNodeIds.has(node.id)) {
|
|
1023
|
+
actions.selectAndDrillDown(node.id);
|
|
1024
|
+
}
|
|
711
1025
|
setContextMenu({ x: e.clientX, y: e.clientY, node });
|
|
712
1026
|
},
|
|
713
|
-
[actions]
|
|
1027
|
+
[actions, state.selectedNodeIds]
|
|
714
1028
|
);
|
|
715
1029
|
const buildContextMenuItems = useCallback3(
|
|
716
1030
|
(node) => {
|
|
@@ -789,7 +1103,7 @@ function TreeView({
|
|
|
789
1103
|
items.push({
|
|
790
1104
|
label: "Delete",
|
|
791
1105
|
action: () => {
|
|
792
|
-
const newTree =
|
|
1106
|
+
const newTree = removeNode3(state.tree, node.id);
|
|
793
1107
|
actions.setTree(newTree);
|
|
794
1108
|
}
|
|
795
1109
|
});
|
|
@@ -801,19 +1115,31 @@ function TreeView({
|
|
|
801
1115
|
const handleKeyDown = useCallback3(
|
|
802
1116
|
(e) => {
|
|
803
1117
|
const currentIndex = visibleNodes.findIndex(
|
|
804
|
-
(n) => n.id === state.
|
|
1118
|
+
(n) => n.id === state.focusedNodeId
|
|
805
1119
|
);
|
|
806
1120
|
switch (e.key) {
|
|
807
1121
|
case "ArrowDown": {
|
|
808
1122
|
e.preventDefault();
|
|
809
1123
|
const next = visibleNodes[currentIndex + 1];
|
|
810
|
-
if (next)
|
|
1124
|
+
if (next) {
|
|
1125
|
+
if (e.shiftKey) {
|
|
1126
|
+
handleSelectRange(next.id);
|
|
1127
|
+
} else {
|
|
1128
|
+
actions.selectNode(next.id);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
811
1131
|
break;
|
|
812
1132
|
}
|
|
813
1133
|
case "ArrowUp": {
|
|
814
1134
|
e.preventDefault();
|
|
815
1135
|
const prev = visibleNodes[currentIndex - 1];
|
|
816
|
-
if (prev)
|
|
1136
|
+
if (prev) {
|
|
1137
|
+
if (e.shiftKey) {
|
|
1138
|
+
handleSelectRange(prev.id);
|
|
1139
|
+
} else {
|
|
1140
|
+
actions.selectNode(prev.id);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
817
1143
|
break;
|
|
818
1144
|
}
|
|
819
1145
|
case "ArrowRight": {
|
|
@@ -840,17 +1166,47 @@ function TreeView({
|
|
|
840
1166
|
}
|
|
841
1167
|
break;
|
|
842
1168
|
}
|
|
1169
|
+
case "a": {
|
|
1170
|
+
if (e.metaKey || e.ctrlKey) {
|
|
1171
|
+
e.preventDefault();
|
|
1172
|
+
const ids = computeSelectAllIds(
|
|
1173
|
+
state.tree,
|
|
1174
|
+
state.focusedNodeId,
|
|
1175
|
+
state.selectedNodeIds
|
|
1176
|
+
);
|
|
1177
|
+
if (ids) {
|
|
1178
|
+
actions.setSelection(
|
|
1179
|
+
state.focusedNodeId,
|
|
1180
|
+
ids,
|
|
1181
|
+
state.focusedNodeId
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
case "Escape": {
|
|
1188
|
+
e.preventDefault();
|
|
1189
|
+
if (state.selectedNodeIds.size > 1 && state.focusedNodeId) {
|
|
1190
|
+
actions.selectNode(state.focusedNodeId);
|
|
1191
|
+
} else {
|
|
1192
|
+
actions.setSelection(null, /* @__PURE__ */ new Set(), null);
|
|
1193
|
+
}
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
843
1196
|
case "Delete":
|
|
844
1197
|
case "Backspace": {
|
|
845
1198
|
e.preventDefault();
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
1199
|
+
const { newTree, nextFocusId } = deleteSelectedNodes(
|
|
1200
|
+
state.tree,
|
|
1201
|
+
state.selectedNodeIds,
|
|
1202
|
+
visibleNodes
|
|
1203
|
+
);
|
|
1204
|
+
if (newTree === state.tree) break;
|
|
1205
|
+
actions.setTree(newTree);
|
|
1206
|
+
if (nextFocusId) {
|
|
1207
|
+
actions.selectNode(nextFocusId);
|
|
1208
|
+
} else {
|
|
1209
|
+
actions.setSelection(null, /* @__PURE__ */ new Set(), null);
|
|
854
1210
|
}
|
|
855
1211
|
break;
|
|
856
1212
|
}
|
|
@@ -858,23 +1214,25 @@ function TreeView({
|
|
|
858
1214
|
},
|
|
859
1215
|
[
|
|
860
1216
|
visibleNodes,
|
|
861
|
-
state.
|
|
1217
|
+
state.focusedNodeId,
|
|
1218
|
+
state.selectedNodeIds,
|
|
862
1219
|
state.expandedNodeIds,
|
|
863
1220
|
state.tree,
|
|
864
|
-
actions
|
|
1221
|
+
actions,
|
|
1222
|
+
handleSelectRange
|
|
865
1223
|
]
|
|
866
1224
|
);
|
|
867
1225
|
const [isFocused, setIsFocused] = useState4(false);
|
|
868
1226
|
useEffect3(() => {
|
|
869
|
-
if (state.
|
|
1227
|
+
if (state.focusedNodeId && containerRef.current) {
|
|
870
1228
|
const el = containerRef.current.querySelector(
|
|
871
|
-
`[data-node-id="${state.
|
|
1229
|
+
`[data-node-id="${state.focusedNodeId}"]`
|
|
872
1230
|
);
|
|
873
1231
|
if (el) {
|
|
874
1232
|
el.scrollIntoView({ block: "nearest" });
|
|
875
1233
|
}
|
|
876
1234
|
}
|
|
877
|
-
}, [state.
|
|
1235
|
+
}, [state.focusedNodeId]);
|
|
878
1236
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
879
1237
|
/* @__PURE__ */ jsx3(
|
|
880
1238
|
"div",
|
|
@@ -904,6 +1262,7 @@ function TreeView({
|
|
|
904
1262
|
showValues,
|
|
905
1263
|
showCounts,
|
|
906
1264
|
isFocused,
|
|
1265
|
+
onSelectRange: handleSelectRange,
|
|
907
1266
|
onDragStart: handleDragStart,
|
|
908
1267
|
onDragOver: handleDragOver,
|
|
909
1268
|
onDragEnd: handleDragEnd,
|
|
@@ -926,25 +1285,25 @@ function TreeView({
|
|
|
926
1285
|
}
|
|
927
1286
|
|
|
928
1287
|
// src/form-view.tsx
|
|
929
|
-
import { useState as useState7, useCallback as useCallback6, useRef as useRef7, useEffect as useEffect6, useMemo as
|
|
1288
|
+
import { useState as useState7, useCallback as useCallback6, useRef as useRef7, useEffect as useEffect6, useMemo as useMemo6 } from "react";
|
|
930
1289
|
import {
|
|
931
1290
|
setValue,
|
|
932
1291
|
setKey,
|
|
933
1292
|
addProperty,
|
|
934
|
-
removeNode as
|
|
935
|
-
getPropertySchema
|
|
1293
|
+
removeNode as removeNode4,
|
|
1294
|
+
getPropertySchema,
|
|
936
1295
|
resolveRef
|
|
937
1296
|
} from "@visual-json/core";
|
|
938
1297
|
|
|
939
1298
|
// src/breadcrumbs.tsx
|
|
940
|
-
import { useState as useState5, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback4, useMemo as
|
|
1299
|
+
import { useState as useState5, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback4, useMemo as useMemo4 } from "react";
|
|
941
1300
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
942
1301
|
var MAX_SUGGESTIONS = 20;
|
|
943
1302
|
var DROPDOWN_MAX_HEIGHT = 200;
|
|
944
1303
|
function Breadcrumbs({ className }) {
|
|
945
1304
|
const { state, actions } = useStudio();
|
|
946
|
-
const
|
|
947
|
-
const currentPath =
|
|
1305
|
+
const drillDownNode = state.drillDownNodeId ? state.tree.nodesById.get(state.drillDownNodeId) : null;
|
|
1306
|
+
const currentPath = drillDownNode?.path ?? "/";
|
|
948
1307
|
const [inputValue, setInputValue] = useState5(currentPath);
|
|
949
1308
|
const [open, setOpen] = useState5(false);
|
|
950
1309
|
const [highlightIndex, setHighlightIndex] = useState5(0);
|
|
@@ -954,7 +1313,7 @@ function Breadcrumbs({ className }) {
|
|
|
954
1313
|
useEffect4(() => {
|
|
955
1314
|
setInputValue(currentPath);
|
|
956
1315
|
}, [currentPath]);
|
|
957
|
-
const suggestions =
|
|
1316
|
+
const suggestions = useMemo4(() => {
|
|
958
1317
|
if (!open) return [];
|
|
959
1318
|
const query = inputValue.toLowerCase();
|
|
960
1319
|
const matches = [];
|
|
@@ -974,7 +1333,7 @@ function Breadcrumbs({ className }) {
|
|
|
974
1333
|
(path) => {
|
|
975
1334
|
for (const [id, node] of state.tree.nodesById) {
|
|
976
1335
|
if (node.path === path) {
|
|
977
|
-
actions.
|
|
1336
|
+
actions.selectAndDrillDown(id);
|
|
978
1337
|
break;
|
|
979
1338
|
}
|
|
980
1339
|
}
|
|
@@ -1062,7 +1421,7 @@ function Breadcrumbs({ className }) {
|
|
|
1062
1421
|
style: {
|
|
1063
1422
|
width: "100%",
|
|
1064
1423
|
boxSizing: "border-box",
|
|
1065
|
-
padding: "
|
|
1424
|
+
padding: "3px 0",
|
|
1066
1425
|
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1067
1426
|
fontFamily: "var(--vj-font, monospace)",
|
|
1068
1427
|
color: "var(--vj-text-muted, #999999)",
|
|
@@ -1124,7 +1483,7 @@ import {
|
|
|
1124
1483
|
useRef as useRef6,
|
|
1125
1484
|
useEffect as useEffect5,
|
|
1126
1485
|
useCallback as useCallback5,
|
|
1127
|
-
useMemo as
|
|
1486
|
+
useMemo as useMemo5
|
|
1128
1487
|
} from "react";
|
|
1129
1488
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1130
1489
|
var DROPDOWN_MAX_HEIGHT2 = 200;
|
|
@@ -1143,7 +1502,7 @@ function EnumInput({
|
|
|
1143
1502
|
useEffect5(() => {
|
|
1144
1503
|
setInputValue(value);
|
|
1145
1504
|
}, [value]);
|
|
1146
|
-
const suggestions =
|
|
1505
|
+
const suggestions = useMemo5(
|
|
1147
1506
|
() => enumValues.map((v) => String(v)),
|
|
1148
1507
|
[enumValues]
|
|
1149
1508
|
);
|
|
@@ -1295,7 +1654,7 @@ function EnumInput({
|
|
|
1295
1654
|
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1296
1655
|
function getResolvedSchema(schema, rootSchema, path) {
|
|
1297
1656
|
if (!schema) return void 0;
|
|
1298
|
-
const raw =
|
|
1657
|
+
const raw = getPropertySchema(schema, path, rootSchema);
|
|
1299
1658
|
if (!raw) return void 0;
|
|
1300
1659
|
return resolveRef(raw, rootSchema ?? schema);
|
|
1301
1660
|
}
|
|
@@ -1318,7 +1677,6 @@ function FormField({
|
|
|
1318
1677
|
depth,
|
|
1319
1678
|
showDescriptions,
|
|
1320
1679
|
showCounts,
|
|
1321
|
-
formSelectedNodeId,
|
|
1322
1680
|
editingNodeId,
|
|
1323
1681
|
collapsedIds,
|
|
1324
1682
|
maxKeyLength,
|
|
@@ -1336,26 +1694,26 @@ function FormField({
|
|
|
1336
1694
|
const { state, actions } = useStudio();
|
|
1337
1695
|
const isContainer = node.type === "object" || node.type === "array";
|
|
1338
1696
|
const collapsed = collapsedIds.has(node.id);
|
|
1339
|
-
const isSelected =
|
|
1697
|
+
const isSelected = state.selectedNodeIds.has(node.id);
|
|
1340
1698
|
const isEditing = editingNodeId === node.id;
|
|
1341
1699
|
const propSchema = getResolvedSchema(schema, rootSchema, node.path);
|
|
1342
1700
|
const isRequired = checkRequired(node, schema, rootSchema);
|
|
1343
1701
|
const [hovered, setHovered] = useState7(false);
|
|
1344
1702
|
const isRoot = node.parentId === null;
|
|
1345
1703
|
const isDragTarget = dragState.dropTargetNodeId === node.id;
|
|
1346
|
-
const isDraggedNode = dragState.
|
|
1704
|
+
const isDraggedNode = dragState.draggedNodeIds.has(node.id);
|
|
1347
1705
|
function handleDragOverEvent(e) {
|
|
1348
1706
|
e.preventDefault();
|
|
1349
1707
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
1350
1708
|
const midY = rect.top + rect.height / 2;
|
|
1351
1709
|
onDragOver(node.id, e.clientY < midY ? "before" : "after");
|
|
1352
1710
|
}
|
|
1353
|
-
let
|
|
1354
|
-
let
|
|
1711
|
+
let borderTopColor = "transparent";
|
|
1712
|
+
let borderBottomColor = "transparent";
|
|
1355
1713
|
if (isDragTarget && dragState.dropPosition === "before") {
|
|
1356
|
-
|
|
1714
|
+
borderTopColor = "var(--vj-accent, #007acc)";
|
|
1357
1715
|
} else if (isDragTarget && dragState.dropPosition === "after") {
|
|
1358
|
-
|
|
1716
|
+
borderBottomColor = "var(--vj-accent, #007acc)";
|
|
1359
1717
|
}
|
|
1360
1718
|
const valueRef = useRef7(null);
|
|
1361
1719
|
const keyRef = useRef7(null);
|
|
@@ -1398,7 +1756,7 @@ function FormField({
|
|
|
1398
1756
|
[state.tree, node.id, actions]
|
|
1399
1757
|
);
|
|
1400
1758
|
const handleRemove = useCallback6(() => {
|
|
1401
|
-
const newTree =
|
|
1759
|
+
const newTree = removeNode4(state.tree, node.id);
|
|
1402
1760
|
actions.setTree(newTree);
|
|
1403
1761
|
}, [state.tree, node.id, actions]);
|
|
1404
1762
|
const handleAddChild = useCallback6(() => {
|
|
@@ -1407,7 +1765,6 @@ function FormField({
|
|
|
1407
1765
|
actions.setTree(newTree);
|
|
1408
1766
|
}, [state.tree, node.id, node.type, node.children.length, actions]);
|
|
1409
1767
|
const description = propSchema?.description;
|
|
1410
|
-
const defaultVal = propSchema?.default;
|
|
1411
1768
|
const isDeprecated = propSchema?.deprecated;
|
|
1412
1769
|
const fieldTitle = propSchema?.title;
|
|
1413
1770
|
const parentIsObject = node.parentId && state.tree.nodesById.get(node.parentId)?.type === "object";
|
|
@@ -1422,6 +1779,9 @@ function FormField({
|
|
|
1422
1779
|
draggable: !isRoot,
|
|
1423
1780
|
onDragStart: (e) => {
|
|
1424
1781
|
e.dataTransfer.effectAllowed = "move";
|
|
1782
|
+
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
1783
|
+
setMultiDragImage(e, state.selectedNodeIds.size);
|
|
1784
|
+
}
|
|
1425
1785
|
onDragStart(node.id);
|
|
1426
1786
|
},
|
|
1427
1787
|
onDragOver: handleDragOverEvent,
|
|
@@ -1434,20 +1794,21 @@ function FormField({
|
|
|
1434
1794
|
display: "flex",
|
|
1435
1795
|
alignItems: "center",
|
|
1436
1796
|
gap: 6,
|
|
1437
|
-
padding: "
|
|
1797
|
+
padding: "1px 8px",
|
|
1438
1798
|
paddingLeft: 8 + depth * 16,
|
|
1439
1799
|
cursor: "pointer",
|
|
1440
1800
|
backgroundColor: rowBg,
|
|
1441
1801
|
color: rowColor,
|
|
1442
1802
|
height: 28,
|
|
1803
|
+
boxSizing: "border-box",
|
|
1443
1804
|
userSelect: "none",
|
|
1444
1805
|
opacity: isDeprecated ? 0.5 : isDraggedNode ? 0.4 : 1,
|
|
1445
|
-
borderTop
|
|
1446
|
-
borderBottom
|
|
1806
|
+
borderTop: `2px solid ${borderTopColor}`,
|
|
1807
|
+
borderBottom: `2px solid ${borderBottomColor}`
|
|
1447
1808
|
},
|
|
1448
1809
|
onClick: (e) => {
|
|
1449
1810
|
e.stopPropagation();
|
|
1450
|
-
onSelect(node.id);
|
|
1811
|
+
onSelect(node.id, e);
|
|
1451
1812
|
},
|
|
1452
1813
|
onDoubleClick: () => onToggleCollapse(node.id),
|
|
1453
1814
|
onMouseEnter: () => setHovered(true),
|
|
@@ -1503,7 +1864,7 @@ function FormField({
|
|
|
1503
1864
|
{
|
|
1504
1865
|
style: {
|
|
1505
1866
|
color: !isRoot && !parentIsObject && !isSelected ? "var(--vj-text-muted, #888888)" : "inherit",
|
|
1506
|
-
fontSize:
|
|
1867
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1507
1868
|
fontFamily: "var(--vj-font, monospace)",
|
|
1508
1869
|
fontWeight: 500,
|
|
1509
1870
|
flexShrink: 0,
|
|
@@ -1604,7 +1965,6 @@ function FormField({
|
|
|
1604
1965
|
depth: depth + 1,
|
|
1605
1966
|
showDescriptions,
|
|
1606
1967
|
showCounts,
|
|
1607
|
-
formSelectedNodeId,
|
|
1608
1968
|
editingNodeId,
|
|
1609
1969
|
collapsedIds,
|
|
1610
1970
|
maxKeyLength,
|
|
@@ -1632,6 +1992,9 @@ function FormField({
|
|
|
1632
1992
|
draggable: !isRoot,
|
|
1633
1993
|
onDragStart: (e) => {
|
|
1634
1994
|
e.dataTransfer.effectAllowed = "move";
|
|
1995
|
+
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
1996
|
+
setMultiDragImage(e, state.selectedNodeIds.size);
|
|
1997
|
+
}
|
|
1635
1998
|
onDragStart(node.id);
|
|
1636
1999
|
},
|
|
1637
2000
|
onDragOver: handleDragOverEvent,
|
|
@@ -1644,20 +2007,21 @@ function FormField({
|
|
|
1644
2007
|
display: "flex",
|
|
1645
2008
|
alignItems: "center",
|
|
1646
2009
|
gap: 6,
|
|
1647
|
-
padding: "
|
|
2010
|
+
padding: "1px 8px",
|
|
1648
2011
|
paddingLeft: 8 + depth * 16,
|
|
1649
2012
|
cursor: "pointer",
|
|
1650
2013
|
backgroundColor: rowBg,
|
|
1651
2014
|
color: rowColor,
|
|
1652
2015
|
height: 28,
|
|
2016
|
+
boxSizing: "border-box",
|
|
1653
2017
|
userSelect: "none",
|
|
1654
2018
|
opacity: isDeprecated ? 0.5 : isDraggedNode ? 0.4 : 1,
|
|
1655
|
-
borderTop
|
|
1656
|
-
borderBottom
|
|
2019
|
+
borderTop: `2px solid ${borderTopColor}`,
|
|
2020
|
+
borderBottom: `2px solid ${borderBottomColor}`
|
|
1657
2021
|
},
|
|
1658
2022
|
onClick: (e) => {
|
|
1659
2023
|
e.stopPropagation();
|
|
1660
|
-
onSelect(node.id);
|
|
2024
|
+
onSelect(node.id, e);
|
|
1661
2025
|
},
|
|
1662
2026
|
onDoubleClick: () => onStartEditing(node.id),
|
|
1663
2027
|
onMouseEnter: () => setHovered(true),
|
|
@@ -1694,7 +2058,7 @@ function FormField({
|
|
|
1694
2058
|
{
|
|
1695
2059
|
style: {
|
|
1696
2060
|
color: !parentIsObject && !isSelected ? "var(--vj-text-muted, #888888)" : "inherit",
|
|
1697
|
-
fontSize:
|
|
2061
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1698
2062
|
fontFamily: "var(--vj-font, monospace)",
|
|
1699
2063
|
flexShrink: 0,
|
|
1700
2064
|
display: "inline-block",
|
|
@@ -1738,7 +2102,7 @@ function FormField({
|
|
|
1738
2102
|
{
|
|
1739
2103
|
style: {
|
|
1740
2104
|
color: valueColor,
|
|
1741
|
-
fontSize:
|
|
2105
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1742
2106
|
fontFamily: "var(--vj-font, monospace)",
|
|
1743
2107
|
overflow: "hidden",
|
|
1744
2108
|
textOverflow: "ellipsis",
|
|
@@ -1816,7 +2180,7 @@ function renderEditInput(node, propSchema, displayValue, handleValueChange, inpu
|
|
|
1816
2180
|
style: {
|
|
1817
2181
|
color: "var(--vj-boolean, #569cd6)",
|
|
1818
2182
|
fontFamily: "var(--vj-font, monospace)",
|
|
1819
|
-
fontSize:
|
|
2183
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1820
2184
|
fontStyle: "italic",
|
|
1821
2185
|
flex: 1
|
|
1822
2186
|
},
|
|
@@ -1849,11 +2213,8 @@ function FormView({
|
|
|
1849
2213
|
}) {
|
|
1850
2214
|
const { state, actions } = useStudio();
|
|
1851
2215
|
const rootSchema = state.schema ?? void 0;
|
|
1852
|
-
const
|
|
1853
|
-
const displayNode =
|
|
1854
|
-
const [formSelectedNodeId, setFormSelectedNodeId] = useState7(
|
|
1855
|
-
null
|
|
1856
|
-
);
|
|
2216
|
+
const drillDownNode = state.drillDownNodeId ? state.tree.nodesById.get(state.drillDownNodeId) : null;
|
|
2217
|
+
const displayNode = drillDownNode ?? state.tree.root;
|
|
1857
2218
|
const [editingNodeId, setEditingNodeId] = useState7(null);
|
|
1858
2219
|
const preEditTreeRef = useRef7(null);
|
|
1859
2220
|
const [collapsedIds, setCollapsedIds] = useState7(
|
|
@@ -1861,23 +2222,26 @@ function FormView({
|
|
|
1861
2222
|
);
|
|
1862
2223
|
const containerRef = useRef7(null);
|
|
1863
2224
|
const [isFocused, setIsFocused] = useState7(false);
|
|
1864
|
-
const {
|
|
1865
|
-
dragState,
|
|
1866
|
-
handleDragStart,
|
|
1867
|
-
handleDragOver,
|
|
1868
|
-
handleDragEnd,
|
|
1869
|
-
handleDrop
|
|
1870
|
-
} = useDragDrop();
|
|
1871
2225
|
useEffect6(() => {
|
|
1872
|
-
setFormSelectedNodeId(null);
|
|
1873
2226
|
setEditingNodeId(null);
|
|
1874
2227
|
setCollapsedIds(/* @__PURE__ */ new Set());
|
|
1875
2228
|
}, [displayNode.id]);
|
|
1876
|
-
const visibleNodes =
|
|
2229
|
+
const visibleNodes = useMemo6(
|
|
1877
2230
|
() => getVisibleNodes(displayNode, (id) => !collapsedIds.has(id)),
|
|
1878
2231
|
[displayNode, collapsedIds]
|
|
1879
2232
|
);
|
|
1880
|
-
const {
|
|
2233
|
+
const {
|
|
2234
|
+
dragState,
|
|
2235
|
+
handleDragStart,
|
|
2236
|
+
handleDragOver,
|
|
2237
|
+
handleDragEnd,
|
|
2238
|
+
handleDrop
|
|
2239
|
+
} = useDragDrop(visibleNodes, state.selectedNodeIds);
|
|
2240
|
+
useEffect6(() => {
|
|
2241
|
+
actions.setVisibleNodesOverride(visibleNodes);
|
|
2242
|
+
return () => actions.setVisibleNodesOverride(null);
|
|
2243
|
+
}, [visibleNodes, actions]);
|
|
2244
|
+
const { maxKeyLength, maxDepth } = useMemo6(() => {
|
|
1881
2245
|
let maxKey = 1;
|
|
1882
2246
|
let maxD = 0;
|
|
1883
2247
|
const baseSegments = displayNode.path === "/" ? 0 : displayNode.path.split("/").filter(Boolean).length;
|
|
@@ -1890,10 +2254,20 @@ function FormView({
|
|
|
1890
2254
|
}
|
|
1891
2255
|
return { maxKeyLength: maxKey, maxDepth: maxD };
|
|
1892
2256
|
}, [visibleNodes, displayNode.path, state.tree]);
|
|
1893
|
-
const handleSelect = useCallback6(
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
2257
|
+
const handleSelect = useCallback6(
|
|
2258
|
+
(nodeId, e) => {
|
|
2259
|
+
setEditingNodeId(null);
|
|
2260
|
+
if (e.shiftKey) {
|
|
2261
|
+
actions.setVisibleNodesOverride(visibleNodes);
|
|
2262
|
+
actions.selectNodeRange(nodeId);
|
|
2263
|
+
} else if (e.metaKey || e.ctrlKey) {
|
|
2264
|
+
actions.toggleNodeSelection(nodeId);
|
|
2265
|
+
} else {
|
|
2266
|
+
actions.selectNode(nodeId);
|
|
2267
|
+
}
|
|
2268
|
+
},
|
|
2269
|
+
[actions, visibleNodes]
|
|
2270
|
+
);
|
|
1897
2271
|
const handleToggleCollapse = useCallback6((nodeId) => {
|
|
1898
2272
|
setCollapsedIds((prev) => {
|
|
1899
2273
|
const next = new Set(prev);
|
|
@@ -1941,15 +2315,23 @@ function FormView({
|
|
|
1941
2315
|
}
|
|
1942
2316
|
return;
|
|
1943
2317
|
}
|
|
1944
|
-
|
|
1945
|
-
(n) => n.id ===
|
|
2318
|
+
let currentIndex = visibleNodes.findIndex(
|
|
2319
|
+
(n) => n.id === state.focusedNodeId
|
|
1946
2320
|
);
|
|
2321
|
+
if (currentIndex === -1 && visibleNodes.length > 0) {
|
|
2322
|
+
currentIndex = 0;
|
|
2323
|
+
}
|
|
1947
2324
|
switch (e.key) {
|
|
1948
2325
|
case "ArrowDown": {
|
|
1949
2326
|
e.preventDefault();
|
|
1950
2327
|
const next = visibleNodes[currentIndex + 1];
|
|
1951
2328
|
if (next) {
|
|
1952
|
-
|
|
2329
|
+
if (e.shiftKey) {
|
|
2330
|
+
actions.setVisibleNodesOverride(visibleNodes);
|
|
2331
|
+
actions.selectNodeRange(next.id);
|
|
2332
|
+
} else {
|
|
2333
|
+
actions.selectNode(next.id);
|
|
2334
|
+
}
|
|
1953
2335
|
scrollToNode(next.id);
|
|
1954
2336
|
}
|
|
1955
2337
|
break;
|
|
@@ -1958,7 +2340,12 @@ function FormView({
|
|
|
1958
2340
|
e.preventDefault();
|
|
1959
2341
|
const prev = visibleNodes[currentIndex - 1];
|
|
1960
2342
|
if (prev) {
|
|
1961
|
-
|
|
2343
|
+
if (e.shiftKey) {
|
|
2344
|
+
actions.setVisibleNodesOverride(visibleNodes);
|
|
2345
|
+
actions.selectNodeRange(prev.id);
|
|
2346
|
+
} else {
|
|
2347
|
+
actions.selectNode(prev.id);
|
|
2348
|
+
}
|
|
1962
2349
|
scrollToNode(prev.id);
|
|
1963
2350
|
}
|
|
1964
2351
|
break;
|
|
@@ -1974,7 +2361,7 @@ function FormView({
|
|
|
1974
2361
|
return next;
|
|
1975
2362
|
});
|
|
1976
2363
|
} else if (node.children.length > 0) {
|
|
1977
|
-
|
|
2364
|
+
actions.selectNode(node.children[0].id);
|
|
1978
2365
|
scrollToNode(node.children[0].id);
|
|
1979
2366
|
}
|
|
1980
2367
|
}
|
|
@@ -1996,7 +2383,7 @@ function FormView({
|
|
|
1996
2383
|
(n) => n.id === current.parentId
|
|
1997
2384
|
);
|
|
1998
2385
|
if (parentInVisible) {
|
|
1999
|
-
|
|
2386
|
+
actions.selectNode(parentInVisible.id);
|
|
2000
2387
|
scrollToNode(parentInVisible.id);
|
|
2001
2388
|
}
|
|
2002
2389
|
}
|
|
@@ -2004,30 +2391,54 @@ function FormView({
|
|
|
2004
2391
|
}
|
|
2005
2392
|
case "Enter": {
|
|
2006
2393
|
e.preventDefault();
|
|
2007
|
-
if (
|
|
2394
|
+
if (state.focusedNodeId) {
|
|
2008
2395
|
preEditTreeRef.current = state.tree;
|
|
2009
|
-
|
|
2396
|
+
actions.selectNode(state.focusedNodeId);
|
|
2397
|
+
setEditingNodeId(state.focusedNodeId);
|
|
2398
|
+
}
|
|
2399
|
+
break;
|
|
2400
|
+
}
|
|
2401
|
+
case "a": {
|
|
2402
|
+
if (e.metaKey || e.ctrlKey) {
|
|
2403
|
+
e.preventDefault();
|
|
2404
|
+
const ids = computeSelectAllIds(
|
|
2405
|
+
state.tree,
|
|
2406
|
+
state.focusedNodeId,
|
|
2407
|
+
state.selectedNodeIds
|
|
2408
|
+
);
|
|
2409
|
+
if (ids) {
|
|
2410
|
+
actions.setSelection(
|
|
2411
|
+
state.focusedNodeId,
|
|
2412
|
+
ids,
|
|
2413
|
+
state.focusedNodeId
|
|
2414
|
+
);
|
|
2415
|
+
}
|
|
2010
2416
|
}
|
|
2011
2417
|
break;
|
|
2012
2418
|
}
|
|
2013
2419
|
case "Escape": {
|
|
2014
2420
|
e.preventDefault();
|
|
2015
|
-
|
|
2421
|
+
if (state.selectedNodeIds.size > 1 && state.focusedNodeId) {
|
|
2422
|
+
actions.selectNode(state.focusedNodeId);
|
|
2423
|
+
} else {
|
|
2424
|
+
actions.setSelection(null, /* @__PURE__ */ new Set(), null);
|
|
2425
|
+
}
|
|
2016
2426
|
break;
|
|
2017
2427
|
}
|
|
2018
2428
|
case "Delete":
|
|
2019
2429
|
case "Backspace": {
|
|
2020
2430
|
e.preventDefault();
|
|
2021
|
-
const
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2431
|
+
const { newTree, nextFocusId } = deleteSelectedNodes(
|
|
2432
|
+
state.tree,
|
|
2433
|
+
state.selectedNodeIds,
|
|
2434
|
+
visibleNodes
|
|
2435
|
+
);
|
|
2436
|
+
if (newTree === state.tree) break;
|
|
2437
|
+
actions.setTree(newTree);
|
|
2438
|
+
if (nextFocusId) {
|
|
2439
|
+
actions.selectNode(nextFocusId);
|
|
2440
|
+
} else {
|
|
2441
|
+
actions.setSelection(null, /* @__PURE__ */ new Set(), null);
|
|
2031
2442
|
}
|
|
2032
2443
|
break;
|
|
2033
2444
|
}
|
|
@@ -2035,7 +2446,8 @@ function FormView({
|
|
|
2035
2446
|
},
|
|
2036
2447
|
[
|
|
2037
2448
|
visibleNodes,
|
|
2038
|
-
|
|
2449
|
+
state.focusedNodeId,
|
|
2450
|
+
state.selectedNodeIds,
|
|
2039
2451
|
editingNodeId,
|
|
2040
2452
|
collapsedIds,
|
|
2041
2453
|
scrollToNode,
|
|
@@ -2060,9 +2472,11 @@ function FormView({
|
|
|
2060
2472
|
"div",
|
|
2061
2473
|
{
|
|
2062
2474
|
style: {
|
|
2475
|
+
display: "flex",
|
|
2476
|
+
alignItems: "center",
|
|
2063
2477
|
padding: "4px 8px",
|
|
2064
2478
|
borderBottom: "1px solid var(--vj-border, #333333)",
|
|
2065
|
-
backgroundColor: "var(--vj-bg
|
|
2479
|
+
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
2066
2480
|
flexShrink: 0
|
|
2067
2481
|
},
|
|
2068
2482
|
children: /* @__PURE__ */ jsx6(Breadcrumbs, {})
|
|
@@ -2095,7 +2509,6 @@ function FormView({
|
|
|
2095
2509
|
depth: 0,
|
|
2096
2510
|
showDescriptions,
|
|
2097
2511
|
showCounts,
|
|
2098
|
-
formSelectedNodeId,
|
|
2099
2512
|
editingNodeId,
|
|
2100
2513
|
collapsedIds,
|
|
2101
2514
|
maxKeyLength,
|
|
@@ -2165,7 +2578,7 @@ function SearchBar({ className }) {
|
|
|
2165
2578
|
alignItems: "center",
|
|
2166
2579
|
gap: 6,
|
|
2167
2580
|
padding: "4px 8px",
|
|
2168
|
-
backgroundColor: "var(--vj-bg
|
|
2581
|
+
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
2169
2582
|
borderBottom: "1px solid var(--vj-border, #333333)"
|
|
2170
2583
|
},
|
|
2171
2584
|
children: [
|
|
@@ -2372,31 +2785,6 @@ function SearchBar({ className }) {
|
|
|
2372
2785
|
|
|
2373
2786
|
// src/json-editor.tsx
|
|
2374
2787
|
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2375
|
-
var DEFAULT_CSS_VARS = {
|
|
2376
|
-
"--vj-bg": "#1e1e1e",
|
|
2377
|
-
"--vj-bg-panel": "#252526",
|
|
2378
|
-
"--vj-bg-hover": "#2a2d2e",
|
|
2379
|
-
"--vj-bg-selected": "#2a5a1e",
|
|
2380
|
-
"--vj-bg-selected-muted": "#2a2d2e",
|
|
2381
|
-
"--vj-bg-match": "#3a3520",
|
|
2382
|
-
"--vj-bg-match-active": "#51502b",
|
|
2383
|
-
"--vj-border": "#333333",
|
|
2384
|
-
"--vj-border-subtle": "#2a2a2a",
|
|
2385
|
-
"--vj-text": "#cccccc",
|
|
2386
|
-
"--vj-text-muted": "#888888",
|
|
2387
|
-
"--vj-text-dim": "#666666",
|
|
2388
|
-
"--vj-text-dimmer": "#555555",
|
|
2389
|
-
"--vj-string": "#ce9178",
|
|
2390
|
-
"--vj-number": "#b5cea8",
|
|
2391
|
-
"--vj-boolean": "#569cd6",
|
|
2392
|
-
"--vj-accent": "#007acc",
|
|
2393
|
-
"--vj-accent-muted": "#094771",
|
|
2394
|
-
"--vj-input-bg": "#3c3c3c",
|
|
2395
|
-
"--vj-input-border": "#555555",
|
|
2396
|
-
"--vj-error": "#f48771",
|
|
2397
|
-
"--vj-font": "monospace",
|
|
2398
|
-
"--vj-input-font-size": "13px"
|
|
2399
|
-
};
|
|
2400
2788
|
function JsonEditor({
|
|
2401
2789
|
value,
|
|
2402
2790
|
defaultValue,
|
|
@@ -2723,440 +3111,10 @@ function EditorLayout({
|
|
|
2723
3111
|
] });
|
|
2724
3112
|
}
|
|
2725
3113
|
|
|
2726
|
-
// src/property-editor.tsx
|
|
2727
|
-
import { useState as useState9, useCallback as useCallback9, useRef as useRef10 } from "react";
|
|
2728
|
-
import {
|
|
2729
|
-
setValue as setValue2,
|
|
2730
|
-
setKey as setKey2,
|
|
2731
|
-
addProperty as addProperty2,
|
|
2732
|
-
removeNode as removeNode3,
|
|
2733
|
-
changeType as changeType2,
|
|
2734
|
-
duplicateNode as duplicateNode2,
|
|
2735
|
-
toJson as toJson3,
|
|
2736
|
-
getPropertySchema as getPropertySchema3,
|
|
2737
|
-
resolveRef as resolveRef2
|
|
2738
|
-
} from "@visual-json/core";
|
|
2739
|
-
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2740
|
-
var ALL_TYPES = [
|
|
2741
|
-
"string",
|
|
2742
|
-
"number",
|
|
2743
|
-
"boolean",
|
|
2744
|
-
"null",
|
|
2745
|
-
"object",
|
|
2746
|
-
"array"
|
|
2747
|
-
];
|
|
2748
|
-
function PropertyRow({ node, schemaProperty }) {
|
|
2749
|
-
const { state, actions } = useStudio();
|
|
2750
|
-
const isContainer = node.type === "object" || node.type === "array";
|
|
2751
|
-
const [hoveredRow, setHoveredRow] = useState9(false);
|
|
2752
|
-
const enumRef = useRef10(null);
|
|
2753
|
-
function handleValueChange(newValue) {
|
|
2754
|
-
let parsed;
|
|
2755
|
-
if (newValue === "null") parsed = null;
|
|
2756
|
-
else if (newValue === "true") parsed = true;
|
|
2757
|
-
else if (newValue === "false") parsed = false;
|
|
2758
|
-
else if ((node.type === "number" || schemaProperty?.type === "number" || schemaProperty?.type === "integer") && !isNaN(Number(newValue)) && newValue.trim() !== "")
|
|
2759
|
-
parsed = Number(newValue);
|
|
2760
|
-
else parsed = newValue;
|
|
2761
|
-
const newTree = setValue2(state.tree, node.id, parsed);
|
|
2762
|
-
actions.setTree(newTree);
|
|
2763
|
-
}
|
|
2764
|
-
function handleKeyChange(newKey) {
|
|
2765
|
-
const newTree = setKey2(state.tree, node.id, newKey);
|
|
2766
|
-
actions.setTree(newTree);
|
|
2767
|
-
}
|
|
2768
|
-
function handleRemove() {
|
|
2769
|
-
const newTree = removeNode3(state.tree, node.id);
|
|
2770
|
-
actions.setTree(newTree);
|
|
2771
|
-
}
|
|
2772
|
-
function handleAddChild() {
|
|
2773
|
-
const key = node.type === "array" ? String(node.children.length) : `key${node.children.length}`;
|
|
2774
|
-
const newTree = addProperty2(state.tree, node.id, key, "");
|
|
2775
|
-
actions.setTree(newTree);
|
|
2776
|
-
}
|
|
2777
|
-
function displayValue() {
|
|
2778
|
-
if (isContainer) {
|
|
2779
|
-
return node.type === "array" ? `[${node.children.length} items]` : `{${node.children.length} keys}`;
|
|
2780
|
-
}
|
|
2781
|
-
if (node.value === null) return "";
|
|
2782
|
-
if (node.value === void 0) return "";
|
|
2783
|
-
if (typeof node.value === "string" && node.value === "") return "";
|
|
2784
|
-
return String(node.value);
|
|
2785
|
-
}
|
|
2786
|
-
const hasEnumValues = schemaProperty?.enum && schemaProperty.enum.length > 0;
|
|
2787
|
-
const description = schemaProperty?.description;
|
|
2788
|
-
return /* @__PURE__ */ jsxs7(
|
|
2789
|
-
"div",
|
|
2790
|
-
{
|
|
2791
|
-
onMouseEnter: () => setHoveredRow(true),
|
|
2792
|
-
onMouseLeave: () => setHoveredRow(false),
|
|
2793
|
-
children: [
|
|
2794
|
-
/* @__PURE__ */ jsxs7(
|
|
2795
|
-
"div",
|
|
2796
|
-
{
|
|
2797
|
-
style: {
|
|
2798
|
-
display: "flex",
|
|
2799
|
-
alignItems: "center",
|
|
2800
|
-
gap: 8,
|
|
2801
|
-
padding: "4px 12px",
|
|
2802
|
-
borderBottom: "1px solid var(--vj-border-subtle, #2a2a2a)",
|
|
2803
|
-
minHeight: 32,
|
|
2804
|
-
backgroundColor: hoveredRow ? "var(--vj-bg-hover, #2a2d2e)" : "transparent"
|
|
2805
|
-
},
|
|
2806
|
-
children: [
|
|
2807
|
-
/* @__PURE__ */ jsx9(
|
|
2808
|
-
"input",
|
|
2809
|
-
{
|
|
2810
|
-
value: node.key,
|
|
2811
|
-
onChange: (e) => handleKeyChange(e.target.value),
|
|
2812
|
-
style: {
|
|
2813
|
-
background: "none",
|
|
2814
|
-
border: "1px solid transparent",
|
|
2815
|
-
borderRadius: 3,
|
|
2816
|
-
color: "var(--vj-text, #cccccc)",
|
|
2817
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2818
|
-
fontSize: "var(--vj-input-font-size, 13px)",
|
|
2819
|
-
padding: "2px 6px",
|
|
2820
|
-
width: 140,
|
|
2821
|
-
flexShrink: 0
|
|
2822
|
-
}
|
|
2823
|
-
}
|
|
2824
|
-
),
|
|
2825
|
-
!isContainer ? hasEnumValues ? /* @__PURE__ */ jsx9(
|
|
2826
|
-
EnumInput,
|
|
2827
|
-
{
|
|
2828
|
-
enumValues: schemaProperty.enum,
|
|
2829
|
-
value: displayValue(),
|
|
2830
|
-
onValueChange: handleValueChange,
|
|
2831
|
-
inputRef: enumRef,
|
|
2832
|
-
inputStyle: {
|
|
2833
|
-
background: "none",
|
|
2834
|
-
border: "1px solid transparent",
|
|
2835
|
-
borderRadius: 3,
|
|
2836
|
-
color: node.type === "string" ? "var(--vj-string, #ce9178)" : "var(--vj-number, #b5cea8)",
|
|
2837
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2838
|
-
fontSize: "var(--vj-input-font-size, 13px)",
|
|
2839
|
-
padding: "2px 6px",
|
|
2840
|
-
flex: 1,
|
|
2841
|
-
outline: "none"
|
|
2842
|
-
}
|
|
2843
|
-
}
|
|
2844
|
-
) : /* @__PURE__ */ jsx9(
|
|
2845
|
-
"input",
|
|
2846
|
-
{
|
|
2847
|
-
value: displayValue(),
|
|
2848
|
-
onChange: (e) => handleValueChange(e.target.value),
|
|
2849
|
-
placeholder: "<value>",
|
|
2850
|
-
style: {
|
|
2851
|
-
background: "none",
|
|
2852
|
-
border: "1px solid transparent",
|
|
2853
|
-
borderRadius: 3,
|
|
2854
|
-
color: node.type === "string" ? "var(--vj-string, #ce9178)" : "var(--vj-number, #b5cea8)",
|
|
2855
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2856
|
-
fontSize: "var(--vj-input-font-size, 13px)",
|
|
2857
|
-
padding: "2px 6px",
|
|
2858
|
-
flex: 1,
|
|
2859
|
-
textAlign: "right"
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
) : /* @__PURE__ */ jsx9(
|
|
2863
|
-
"span",
|
|
2864
|
-
{
|
|
2865
|
-
style: {
|
|
2866
|
-
color: "var(--vj-text-dim, #666666)",
|
|
2867
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2868
|
-
fontSize: 13,
|
|
2869
|
-
flex: 1,
|
|
2870
|
-
textAlign: "right"
|
|
2871
|
-
},
|
|
2872
|
-
children: displayValue()
|
|
2873
|
-
}
|
|
2874
|
-
),
|
|
2875
|
-
/* @__PURE__ */ jsxs7(
|
|
2876
|
-
"div",
|
|
2877
|
-
{
|
|
2878
|
-
style: {
|
|
2879
|
-
display: "flex",
|
|
2880
|
-
gap: 2,
|
|
2881
|
-
opacity: hoveredRow ? 1 : 0,
|
|
2882
|
-
transition: "opacity 0.1s",
|
|
2883
|
-
flexShrink: 0
|
|
2884
|
-
},
|
|
2885
|
-
children: [
|
|
2886
|
-
isContainer && /* @__PURE__ */ jsx9(
|
|
2887
|
-
"button",
|
|
2888
|
-
{
|
|
2889
|
-
onClick: handleAddChild,
|
|
2890
|
-
style: {
|
|
2891
|
-
background: "none",
|
|
2892
|
-
border: "none",
|
|
2893
|
-
color: "var(--vj-text-muted, #888888)",
|
|
2894
|
-
cursor: "pointer",
|
|
2895
|
-
padding: "2px 4px",
|
|
2896
|
-
fontSize: 15,
|
|
2897
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2898
|
-
borderRadius: 3,
|
|
2899
|
-
lineHeight: 1
|
|
2900
|
-
},
|
|
2901
|
-
title: "Add child",
|
|
2902
|
-
children: "+"
|
|
2903
|
-
}
|
|
2904
|
-
),
|
|
2905
|
-
/* @__PURE__ */ jsx9(
|
|
2906
|
-
"button",
|
|
2907
|
-
{
|
|
2908
|
-
onClick: handleRemove,
|
|
2909
|
-
style: {
|
|
2910
|
-
background: "none",
|
|
2911
|
-
border: "none",
|
|
2912
|
-
color: "var(--vj-text-muted, #888888)",
|
|
2913
|
-
cursor: "pointer",
|
|
2914
|
-
padding: "2px 4px",
|
|
2915
|
-
fontSize: 15,
|
|
2916
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2917
|
-
borderRadius: 3,
|
|
2918
|
-
lineHeight: 1
|
|
2919
|
-
},
|
|
2920
|
-
title: "Remove",
|
|
2921
|
-
children: "\xD7"
|
|
2922
|
-
}
|
|
2923
|
-
)
|
|
2924
|
-
]
|
|
2925
|
-
}
|
|
2926
|
-
)
|
|
2927
|
-
]
|
|
2928
|
-
}
|
|
2929
|
-
),
|
|
2930
|
-
description && /* @__PURE__ */ jsx9(
|
|
2931
|
-
"div",
|
|
2932
|
-
{
|
|
2933
|
-
style: {
|
|
2934
|
-
padding: "2px 12px 4px 44px",
|
|
2935
|
-
fontSize: 11,
|
|
2936
|
-
color: "var(--vj-text-dim, #666666)",
|
|
2937
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2938
|
-
borderBottom: "1px solid var(--vj-border-subtle, #2a2a2a)"
|
|
2939
|
-
},
|
|
2940
|
-
children: description
|
|
2941
|
-
}
|
|
2942
|
-
)
|
|
2943
|
-
]
|
|
2944
|
-
}
|
|
2945
|
-
);
|
|
2946
|
-
}
|
|
2947
|
-
function PropertyEditor({ className }) {
|
|
2948
|
-
const { state, actions } = useStudio();
|
|
2949
|
-
const selectedNode = state.selectedNodeId ? state.tree.nodesById.get(state.selectedNodeId) : null;
|
|
2950
|
-
const handleChangeType = useCallback9(
|
|
2951
|
-
(newType) => {
|
|
2952
|
-
if (!selectedNode) return;
|
|
2953
|
-
const newTree = changeType2(state.tree, selectedNode.id, newType);
|
|
2954
|
-
actions.setTree(newTree);
|
|
2955
|
-
},
|
|
2956
|
-
[state.tree, selectedNode, actions]
|
|
2957
|
-
);
|
|
2958
|
-
const handleDuplicate = useCallback9(() => {
|
|
2959
|
-
if (!selectedNode) return;
|
|
2960
|
-
const newTree = duplicateNode2(state.tree, selectedNode.id);
|
|
2961
|
-
actions.setTree(newTree);
|
|
2962
|
-
}, [state.tree, selectedNode, actions]);
|
|
2963
|
-
const handleCopyPath = useCallback9(() => {
|
|
2964
|
-
if (!selectedNode) return;
|
|
2965
|
-
navigator.clipboard.writeText(selectedNode.path).catch(() => {
|
|
2966
|
-
});
|
|
2967
|
-
}, [selectedNode]);
|
|
2968
|
-
const handleCopyValue = useCallback9(() => {
|
|
2969
|
-
if (!selectedNode) return;
|
|
2970
|
-
const value = toJson3(selectedNode);
|
|
2971
|
-
const text = typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
2972
|
-
navigator.clipboard.writeText(text).catch(() => {
|
|
2973
|
-
});
|
|
2974
|
-
}, [selectedNode]);
|
|
2975
|
-
if (!selectedNode) {
|
|
2976
|
-
return /* @__PURE__ */ jsx9(
|
|
2977
|
-
"div",
|
|
2978
|
-
{
|
|
2979
|
-
className,
|
|
2980
|
-
style: {
|
|
2981
|
-
display: "flex",
|
|
2982
|
-
alignItems: "center",
|
|
2983
|
-
justifyContent: "center",
|
|
2984
|
-
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
2985
|
-
color: "var(--vj-text-dimmer, #555555)",
|
|
2986
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2987
|
-
fontSize: 13,
|
|
2988
|
-
height: "100%"
|
|
2989
|
-
},
|
|
2990
|
-
children: "Select a node to edit"
|
|
2991
|
-
}
|
|
2992
|
-
);
|
|
2993
|
-
}
|
|
2994
|
-
const isContainer = selectedNode.type === "object" || selectedNode.type === "array";
|
|
2995
|
-
const schema = state.schema ?? void 0;
|
|
2996
|
-
const schemaTitle = schema?.title;
|
|
2997
|
-
function getChildSchema(childKey) {
|
|
2998
|
-
if (!schema || !selectedNode) return void 0;
|
|
2999
|
-
const childPath = selectedNode.path === "/" ? `/${childKey}` : `${selectedNode.path}/${childKey}`;
|
|
3000
|
-
const raw = getPropertySchema3(schema, childPath);
|
|
3001
|
-
return raw ? resolveRef2(raw, schema) : void 0;
|
|
3002
|
-
}
|
|
3003
|
-
function handleAdd() {
|
|
3004
|
-
if (!selectedNode) return;
|
|
3005
|
-
const key = selectedNode.type === "array" ? String(selectedNode.children.length) : `key${selectedNode.children.length}`;
|
|
3006
|
-
const newTree = addProperty2(state.tree, selectedNode.id, key, "");
|
|
3007
|
-
actions.setTree(newTree);
|
|
3008
|
-
}
|
|
3009
|
-
return /* @__PURE__ */ jsxs7(
|
|
3010
|
-
"div",
|
|
3011
|
-
{
|
|
3012
|
-
className,
|
|
3013
|
-
style: {
|
|
3014
|
-
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
3015
|
-
color: "var(--vj-text, #cccccc)",
|
|
3016
|
-
overflow: "auto",
|
|
3017
|
-
height: "100%",
|
|
3018
|
-
display: "flex",
|
|
3019
|
-
flexDirection: "column"
|
|
3020
|
-
},
|
|
3021
|
-
children: [
|
|
3022
|
-
/* @__PURE__ */ jsxs7(
|
|
3023
|
-
"div",
|
|
3024
|
-
{
|
|
3025
|
-
style: {
|
|
3026
|
-
display: "flex",
|
|
3027
|
-
alignItems: "center",
|
|
3028
|
-
justifyContent: "space-between",
|
|
3029
|
-
padding: "6px 12px",
|
|
3030
|
-
borderBottom: "1px solid var(--vj-border, #333333)",
|
|
3031
|
-
fontSize: 12,
|
|
3032
|
-
color: "var(--vj-text-muted, #999999)",
|
|
3033
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
3034
|
-
flexShrink: 0,
|
|
3035
|
-
backgroundColor: "var(--vj-bg-panel, #252526)"
|
|
3036
|
-
},
|
|
3037
|
-
children: [
|
|
3038
|
-
/* @__PURE__ */ jsxs7(
|
|
3039
|
-
"div",
|
|
3040
|
-
{
|
|
3041
|
-
style: {
|
|
3042
|
-
display: "flex",
|
|
3043
|
-
flexDirection: "column",
|
|
3044
|
-
gap: 2,
|
|
3045
|
-
flex: 1,
|
|
3046
|
-
minWidth: 0
|
|
3047
|
-
},
|
|
3048
|
-
children: [
|
|
3049
|
-
/* @__PURE__ */ jsx9(Breadcrumbs, {}),
|
|
3050
|
-
schemaTitle && /* @__PURE__ */ jsx9(
|
|
3051
|
-
"span",
|
|
3052
|
-
{
|
|
3053
|
-
style: { fontSize: 10, color: "var(--vj-text-dim, #666666)" },
|
|
3054
|
-
children: schemaTitle
|
|
3055
|
-
}
|
|
3056
|
-
)
|
|
3057
|
-
]
|
|
3058
|
-
}
|
|
3059
|
-
),
|
|
3060
|
-
/* @__PURE__ */ jsxs7(
|
|
3061
|
-
"div",
|
|
3062
|
-
{
|
|
3063
|
-
style: {
|
|
3064
|
-
display: "flex",
|
|
3065
|
-
alignItems: "center",
|
|
3066
|
-
gap: 4,
|
|
3067
|
-
flexShrink: 0
|
|
3068
|
-
},
|
|
3069
|
-
children: [
|
|
3070
|
-
/* @__PURE__ */ jsx9(
|
|
3071
|
-
"select",
|
|
3072
|
-
{
|
|
3073
|
-
value: selectedNode.type,
|
|
3074
|
-
onChange: (e) => handleChangeType(e.target.value),
|
|
3075
|
-
style: {
|
|
3076
|
-
background: "var(--vj-input-bg, #3c3c3c)",
|
|
3077
|
-
border: "1px solid var(--vj-input-border, #555555)",
|
|
3078
|
-
borderRadius: 3,
|
|
3079
|
-
color: "var(--vj-text, #cccccc)",
|
|
3080
|
-
fontSize: "var(--vj-input-font-size, 13px)",
|
|
3081
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
3082
|
-
padding: "1px 4px",
|
|
3083
|
-
cursor: "pointer"
|
|
3084
|
-
},
|
|
3085
|
-
title: "Change type",
|
|
3086
|
-
children: ALL_TYPES.map((t) => /* @__PURE__ */ jsx9("option", { value: t, children: t }, t))
|
|
3087
|
-
}
|
|
3088
|
-
),
|
|
3089
|
-
/* @__PURE__ */ jsx9(
|
|
3090
|
-
"button",
|
|
3091
|
-
{
|
|
3092
|
-
onClick: handleCopyPath,
|
|
3093
|
-
style: actionButtonStyle,
|
|
3094
|
-
title: "Copy path",
|
|
3095
|
-
children: "path"
|
|
3096
|
-
}
|
|
3097
|
-
),
|
|
3098
|
-
/* @__PURE__ */ jsx9(
|
|
3099
|
-
"button",
|
|
3100
|
-
{
|
|
3101
|
-
onClick: handleCopyValue,
|
|
3102
|
-
style: actionButtonStyle,
|
|
3103
|
-
title: "Copy value",
|
|
3104
|
-
children: "value"
|
|
3105
|
-
}
|
|
3106
|
-
),
|
|
3107
|
-
selectedNode.parentId && /* @__PURE__ */ jsx9(
|
|
3108
|
-
"button",
|
|
3109
|
-
{
|
|
3110
|
-
onClick: handleDuplicate,
|
|
3111
|
-
style: actionButtonStyle,
|
|
3112
|
-
title: "Duplicate",
|
|
3113
|
-
children: "dup"
|
|
3114
|
-
}
|
|
3115
|
-
),
|
|
3116
|
-
isContainer && /* @__PURE__ */ jsx9(
|
|
3117
|
-
"button",
|
|
3118
|
-
{
|
|
3119
|
-
onClick: handleAdd,
|
|
3120
|
-
style: {
|
|
3121
|
-
...actionButtonStyle,
|
|
3122
|
-
border: "1px solid var(--vj-input-border, #555555)"
|
|
3123
|
-
},
|
|
3124
|
-
children: "+ Add"
|
|
3125
|
-
}
|
|
3126
|
-
)
|
|
3127
|
-
]
|
|
3128
|
-
}
|
|
3129
|
-
)
|
|
3130
|
-
]
|
|
3131
|
-
}
|
|
3132
|
-
),
|
|
3133
|
-
/* @__PURE__ */ jsx9("div", { style: { flex: 1, overflow: "auto" }, children: isContainer ? selectedNode.children.map((child) => /* @__PURE__ */ jsx9(
|
|
3134
|
-
PropertyRow,
|
|
3135
|
-
{
|
|
3136
|
-
node: child,
|
|
3137
|
-
schemaProperty: getChildSchema(child.key)
|
|
3138
|
-
},
|
|
3139
|
-
child.id
|
|
3140
|
-
)) : /* @__PURE__ */ jsx9(PropertyRow, { node: selectedNode }) })
|
|
3141
|
-
]
|
|
3142
|
-
}
|
|
3143
|
-
);
|
|
3144
|
-
}
|
|
3145
|
-
var actionButtonStyle = {
|
|
3146
|
-
background: "none",
|
|
3147
|
-
border: "none",
|
|
3148
|
-
borderRadius: 3,
|
|
3149
|
-
color: "var(--vj-text-muted, #888888)",
|
|
3150
|
-
cursor: "pointer",
|
|
3151
|
-
padding: "1px 6px",
|
|
3152
|
-
fontSize: 11,
|
|
3153
|
-
fontFamily: "var(--vj-font, monospace)"
|
|
3154
|
-
};
|
|
3155
|
-
|
|
3156
3114
|
// src/diff-view.tsx
|
|
3157
|
-
import { useMemo as
|
|
3115
|
+
import { useMemo as useMemo7 } from "react";
|
|
3158
3116
|
import { computeDiff } from "@visual-json/core";
|
|
3159
|
-
import { Fragment as Fragment3, jsx as
|
|
3117
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3160
3118
|
var DIFF_COLORS = {
|
|
3161
3119
|
added: { bg: "#1e3a1e", marker: "+", label: "#4ec94e" },
|
|
3162
3120
|
removed: { bg: "#3a1e1e", marker: "-", label: "#f48771" },
|
|
@@ -3177,7 +3135,7 @@ function formatValue(value) {
|
|
|
3177
3135
|
}
|
|
3178
3136
|
function DiffRow({ entry }) {
|
|
3179
3137
|
const colors = DIFF_COLORS[entry.type];
|
|
3180
|
-
return /* @__PURE__ */
|
|
3138
|
+
return /* @__PURE__ */ jsxs7(
|
|
3181
3139
|
"div",
|
|
3182
3140
|
{
|
|
3183
3141
|
style: {
|
|
@@ -3191,7 +3149,7 @@ function DiffRow({ entry }) {
|
|
|
3191
3149
|
gap: 8
|
|
3192
3150
|
},
|
|
3193
3151
|
children: [
|
|
3194
|
-
/* @__PURE__ */
|
|
3152
|
+
/* @__PURE__ */ jsx9(
|
|
3195
3153
|
"span",
|
|
3196
3154
|
{
|
|
3197
3155
|
style: {
|
|
@@ -3204,7 +3162,7 @@ function DiffRow({ entry }) {
|
|
|
3204
3162
|
children: colors.marker
|
|
3205
3163
|
}
|
|
3206
3164
|
),
|
|
3207
|
-
/* @__PURE__ */
|
|
3165
|
+
/* @__PURE__ */ jsx9(
|
|
3208
3166
|
"span",
|
|
3209
3167
|
{
|
|
3210
3168
|
style: {
|
|
@@ -3215,14 +3173,14 @@ function DiffRow({ entry }) {
|
|
|
3215
3173
|
children: entry.path
|
|
3216
3174
|
}
|
|
3217
3175
|
),
|
|
3218
|
-
/* @__PURE__ */
|
|
3219
|
-
entry.type === "changed" && /* @__PURE__ */
|
|
3220
|
-
/* @__PURE__ */
|
|
3221
|
-
/* @__PURE__ */
|
|
3222
|
-
/* @__PURE__ */
|
|
3176
|
+
/* @__PURE__ */ jsxs7("span", { style: { flex: 1, display: "flex", gap: 8, overflow: "hidden" }, children: [
|
|
3177
|
+
entry.type === "changed" && /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
3178
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#f48771", textDecoration: "line-through" }, children: formatValue(entry.oldValue) }),
|
|
3179
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "var(--vj-text-dim, #666666)" }, children: "\u2192" }),
|
|
3180
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#4ec94e" }, children: formatValue(entry.newValue) })
|
|
3223
3181
|
] }),
|
|
3224
|
-
entry.type === "added" && /* @__PURE__ */
|
|
3225
|
-
entry.type === "removed" && /* @__PURE__ */
|
|
3182
|
+
entry.type === "added" && /* @__PURE__ */ jsx9("span", { style: { color: "#4ec94e" }, children: formatValue(entry.newValue) }),
|
|
3183
|
+
entry.type === "removed" && /* @__PURE__ */ jsx9("span", { style: { color: "#f48771", textDecoration: "line-through" }, children: formatValue(entry.oldValue) })
|
|
3226
3184
|
] })
|
|
3227
3185
|
]
|
|
3228
3186
|
}
|
|
@@ -3233,14 +3191,14 @@ function DiffView({
|
|
|
3233
3191
|
currentJson,
|
|
3234
3192
|
className
|
|
3235
3193
|
}) {
|
|
3236
|
-
const entries =
|
|
3194
|
+
const entries = useMemo7(
|
|
3237
3195
|
() => computeDiff(originalJson, currentJson),
|
|
3238
3196
|
[originalJson, currentJson]
|
|
3239
3197
|
);
|
|
3240
3198
|
const added = entries.filter((e) => e.type === "added").length;
|
|
3241
3199
|
const removed = entries.filter((e) => e.type === "removed").length;
|
|
3242
3200
|
const changed = entries.filter((e) => e.type === "changed").length;
|
|
3243
|
-
return /* @__PURE__ */
|
|
3201
|
+
return /* @__PURE__ */ jsxs7(
|
|
3244
3202
|
"div",
|
|
3245
3203
|
{
|
|
3246
3204
|
className,
|
|
@@ -3253,7 +3211,7 @@ function DiffView({
|
|
|
3253
3211
|
flexDirection: "column"
|
|
3254
3212
|
},
|
|
3255
3213
|
children: [
|
|
3256
|
-
/* @__PURE__ */
|
|
3214
|
+
/* @__PURE__ */ jsxs7(
|
|
3257
3215
|
"div",
|
|
3258
3216
|
{
|
|
3259
3217
|
style: {
|
|
@@ -3268,18 +3226,18 @@ function DiffView({
|
|
|
3268
3226
|
flexShrink: 0
|
|
3269
3227
|
},
|
|
3270
3228
|
children: [
|
|
3271
|
-
/* @__PURE__ */
|
|
3272
|
-
added > 0 && /* @__PURE__ */
|
|
3229
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "var(--vj-text-muted, #999999)" }, children: entries.length === 0 ? "No changes" : `${entries.length} changes` }),
|
|
3230
|
+
added > 0 && /* @__PURE__ */ jsxs7("span", { style: { color: "#4ec94e" }, children: [
|
|
3273
3231
|
"+",
|
|
3274
3232
|
added,
|
|
3275
3233
|
" added"
|
|
3276
3234
|
] }),
|
|
3277
|
-
removed > 0 && /* @__PURE__ */
|
|
3235
|
+
removed > 0 && /* @__PURE__ */ jsxs7("span", { style: { color: "#f48771" }, children: [
|
|
3278
3236
|
"-",
|
|
3279
3237
|
removed,
|
|
3280
3238
|
" removed"
|
|
3281
3239
|
] }),
|
|
3282
|
-
changed > 0 && /* @__PURE__ */
|
|
3240
|
+
changed > 0 && /* @__PURE__ */ jsxs7("span", { style: { color: "#dcdcaa" }, children: [
|
|
3283
3241
|
"~",
|
|
3284
3242
|
changed,
|
|
3285
3243
|
" modified"
|
|
@@ -3287,7 +3245,7 @@ function DiffView({
|
|
|
3287
3245
|
]
|
|
3288
3246
|
}
|
|
3289
3247
|
),
|
|
3290
|
-
/* @__PURE__ */
|
|
3248
|
+
/* @__PURE__ */ jsx9("div", { style: { flex: 1, overflow: "auto" }, children: entries.length === 0 ? /* @__PURE__ */ jsx9(
|
|
3291
3249
|
"div",
|
|
3292
3250
|
{
|
|
3293
3251
|
style: {
|
|
@@ -3301,7 +3259,7 @@ function DiffView({
|
|
|
3301
3259
|
},
|
|
3302
3260
|
children: "No differences detected"
|
|
3303
3261
|
}
|
|
3304
|
-
) : entries.map((entry, i) => /* @__PURE__ */
|
|
3262
|
+
) : entries.map((entry, i) => /* @__PURE__ */ jsx9(DiffRow, { entry }, i)) })
|
|
3305
3263
|
]
|
|
3306
3264
|
}
|
|
3307
3265
|
);
|
|
@@ -3312,7 +3270,6 @@ export {
|
|
|
3312
3270
|
DiffView,
|
|
3313
3271
|
FormView,
|
|
3314
3272
|
JsonEditor,
|
|
3315
|
-
PropertyEditor,
|
|
3316
3273
|
SearchBar,
|
|
3317
3274
|
StudioContext,
|
|
3318
3275
|
TreeView,
|