@visual-json/react 0.1.0 → 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 +979 -846
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +989 -856
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -3
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/json-editor.tsx
|
|
2
2
|
import {
|
|
3
|
-
useState as
|
|
4
|
-
useRef as
|
|
5
|
-
useCallback as
|
|
6
|
-
useEffect as
|
|
3
|
+
useState as useState8,
|
|
4
|
+
useRef as useRef9,
|
|
5
|
+
useCallback as useCallback8,
|
|
6
|
+
useEffect as useEffect8
|
|
7
7
|
} from "react";
|
|
8
8
|
|
|
9
9
|
// src/visual-json.tsx
|
|
@@ -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
|
|
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,8 +1421,8 @@ function Breadcrumbs({ className }) {
|
|
|
1062
1421
|
style: {
|
|
1063
1422
|
width: "100%",
|
|
1064
1423
|
boxSizing: "border-box",
|
|
1065
|
-
padding: "
|
|
1066
|
-
fontSize:
|
|
1424
|
+
padding: "3px 0",
|
|
1425
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1067
1426
|
fontFamily: "var(--vj-font, monospace)",
|
|
1068
1427
|
color: "var(--vj-text-muted, #999999)",
|
|
1069
1428
|
background: "transparent",
|
|
@@ -1118,88 +1477,260 @@ function Breadcrumbs({ className }) {
|
|
|
1118
1477
|
);
|
|
1119
1478
|
}
|
|
1120
1479
|
|
|
1121
|
-
// src/
|
|
1480
|
+
// src/enum-input.tsx
|
|
1481
|
+
import {
|
|
1482
|
+
useState as useState6,
|
|
1483
|
+
useRef as useRef6,
|
|
1484
|
+
useEffect as useEffect5,
|
|
1485
|
+
useCallback as useCallback5,
|
|
1486
|
+
useMemo as useMemo5
|
|
1487
|
+
} from "react";
|
|
1122
1488
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
if (node.type === "boolean" || node.type === "null")
|
|
1131
|
-
return "var(--vj-boolean, #569cd6)";
|
|
1132
|
-
if (node.type === "number") return "var(--vj-number, #b5cea8)";
|
|
1133
|
-
return "var(--vj-string, #ce9178)";
|
|
1134
|
-
}
|
|
1135
|
-
function getDisplayValue(node) {
|
|
1136
|
-
if (node.type === "null") return "null";
|
|
1137
|
-
if (node.type === "boolean") return String(node.value);
|
|
1138
|
-
if (node.value === null || node.value === void 0) return "";
|
|
1139
|
-
return String(node.value);
|
|
1140
|
-
}
|
|
1141
|
-
function FormField({
|
|
1142
|
-
node,
|
|
1143
|
-
schema,
|
|
1144
|
-
rootSchema,
|
|
1145
|
-
depth,
|
|
1146
|
-
showDescriptions,
|
|
1147
|
-
showCounts,
|
|
1148
|
-
formSelectedNodeId,
|
|
1149
|
-
editingNodeId,
|
|
1150
|
-
collapsedIds,
|
|
1151
|
-
maxKeyLength,
|
|
1152
|
-
maxDepth,
|
|
1153
|
-
isFocused,
|
|
1154
|
-
dragState,
|
|
1155
|
-
onSelect,
|
|
1156
|
-
onToggleCollapse,
|
|
1157
|
-
onStartEditing,
|
|
1158
|
-
onDragStart,
|
|
1159
|
-
onDragOver,
|
|
1160
|
-
onDragEnd,
|
|
1161
|
-
onDrop
|
|
1489
|
+
var DROPDOWN_MAX_HEIGHT2 = 200;
|
|
1490
|
+
function EnumInput({
|
|
1491
|
+
enumValues,
|
|
1492
|
+
value,
|
|
1493
|
+
onValueChange,
|
|
1494
|
+
inputRef,
|
|
1495
|
+
inputStyle
|
|
1162
1496
|
}) {
|
|
1163
|
-
const
|
|
1164
|
-
const
|
|
1165
|
-
const
|
|
1166
|
-
const
|
|
1167
|
-
const
|
|
1168
|
-
const propSchema = getResolvedSchema(schema, rootSchema, node.path);
|
|
1169
|
-
const isRequired = checkRequired(node, schema, rootSchema);
|
|
1170
|
-
const [hovered, setHovered] = useState6(false);
|
|
1171
|
-
const isRoot = node.parentId === null;
|
|
1172
|
-
const isDragTarget = dragState.dropTargetNodeId === node.id;
|
|
1173
|
-
const isDraggedNode = dragState.draggedNodeId === node.id;
|
|
1174
|
-
function handleDragOverEvent(e) {
|
|
1175
|
-
e.preventDefault();
|
|
1176
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
1177
|
-
const midY = rect.top + rect.height / 2;
|
|
1178
|
-
onDragOver(node.id, e.clientY < midY ? "before" : "after");
|
|
1179
|
-
}
|
|
1180
|
-
let borderTop = "none";
|
|
1181
|
-
let borderBottom = "none";
|
|
1182
|
-
if (isDragTarget && dragState.dropPosition === "before") {
|
|
1183
|
-
borderTop = "2px solid var(--vj-accent, #007acc)";
|
|
1184
|
-
} else if (isDragTarget && dragState.dropPosition === "after") {
|
|
1185
|
-
borderBottom = "2px solid var(--vj-accent, #007acc)";
|
|
1186
|
-
}
|
|
1187
|
-
const valueRef = useRef6(null);
|
|
1188
|
-
const keyRef = useRef6(null);
|
|
1497
|
+
const [inputValue, setInputValue] = useState6(value);
|
|
1498
|
+
const [open, setOpen] = useState6(false);
|
|
1499
|
+
const [highlightIndex, setHighlightIndex] = useState6(0);
|
|
1500
|
+
const listRef = useRef6(null);
|
|
1501
|
+
const wrapperRef = useRef6(null);
|
|
1189
1502
|
useEffect5(() => {
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1503
|
+
setInputValue(value);
|
|
1504
|
+
}, [value]);
|
|
1505
|
+
const suggestions = useMemo5(
|
|
1506
|
+
() => enumValues.map((v) => String(v)),
|
|
1507
|
+
[enumValues]
|
|
1508
|
+
);
|
|
1509
|
+
useEffect5(() => {
|
|
1510
|
+
setHighlightIndex(0);
|
|
1511
|
+
}, [suggestions]);
|
|
1512
|
+
const selectValue = useCallback5(
|
|
1513
|
+
(val) => {
|
|
1514
|
+
onValueChange(val);
|
|
1515
|
+
setInputValue(val);
|
|
1516
|
+
setOpen(false);
|
|
1517
|
+
},
|
|
1518
|
+
[onValueChange]
|
|
1519
|
+
);
|
|
1520
|
+
const handleKeyDown = useCallback5(
|
|
1521
|
+
(e) => {
|
|
1522
|
+
if (!open) {
|
|
1523
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
1524
|
+
e.preventDefault();
|
|
1525
|
+
e.stopPropagation();
|
|
1526
|
+
setOpen(true);
|
|
1527
|
+
}
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
switch (e.key) {
|
|
1531
|
+
case "ArrowDown":
|
|
1532
|
+
e.preventDefault();
|
|
1533
|
+
e.stopPropagation();
|
|
1534
|
+
setHighlightIndex((i) => Math.min(i + 1, suggestions.length - 1));
|
|
1535
|
+
break;
|
|
1536
|
+
case "ArrowUp":
|
|
1537
|
+
e.preventDefault();
|
|
1538
|
+
e.stopPropagation();
|
|
1539
|
+
setHighlightIndex((i) => Math.max(i - 1, 0));
|
|
1540
|
+
break;
|
|
1541
|
+
case "Enter":
|
|
1542
|
+
e.preventDefault();
|
|
1543
|
+
e.stopPropagation();
|
|
1544
|
+
if (suggestions.length > 0 && highlightIndex < suggestions.length) {
|
|
1545
|
+
selectValue(suggestions[highlightIndex]);
|
|
1546
|
+
}
|
|
1547
|
+
break;
|
|
1548
|
+
case "Escape":
|
|
1549
|
+
e.preventDefault();
|
|
1550
|
+
e.stopPropagation();
|
|
1551
|
+
setInputValue(value);
|
|
1552
|
+
setOpen(false);
|
|
1553
|
+
break;
|
|
1554
|
+
case "Tab":
|
|
1555
|
+
setInputValue(value);
|
|
1556
|
+
setOpen(false);
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
[open, suggestions, highlightIndex, value, selectValue]
|
|
1561
|
+
);
|
|
1562
|
+
useEffect5(() => {
|
|
1563
|
+
const el = listRef.current;
|
|
1564
|
+
if (!el || !open) return;
|
|
1565
|
+
const item = el.children[highlightIndex];
|
|
1566
|
+
item?.scrollIntoView({ block: "nearest" });
|
|
1567
|
+
}, [highlightIndex, open]);
|
|
1568
|
+
useEffect5(() => {
|
|
1569
|
+
function handleClickOutside(e) {
|
|
1570
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
|
|
1571
|
+
setInputValue(value);
|
|
1572
|
+
setOpen(false);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1576
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1577
|
+
}, [value]);
|
|
1578
|
+
return /* @__PURE__ */ jsxs3(
|
|
1579
|
+
"div",
|
|
1580
|
+
{
|
|
1581
|
+
ref: wrapperRef,
|
|
1582
|
+
style: { position: "relative", flex: 1, minWidth: 0 },
|
|
1583
|
+
children: [
|
|
1584
|
+
/* @__PURE__ */ jsx5(
|
|
1585
|
+
"input",
|
|
1586
|
+
{
|
|
1587
|
+
ref: inputRef,
|
|
1588
|
+
value: inputValue,
|
|
1589
|
+
onChange: (e) => {
|
|
1590
|
+
setInputValue(e.target.value);
|
|
1591
|
+
if (!open) setOpen(true);
|
|
1592
|
+
},
|
|
1593
|
+
onFocus: () => setOpen(true),
|
|
1594
|
+
onKeyDown: handleKeyDown,
|
|
1595
|
+
onClick: (e) => e.stopPropagation(),
|
|
1596
|
+
spellCheck: false,
|
|
1597
|
+
autoComplete: "off",
|
|
1598
|
+
style: inputStyle
|
|
1599
|
+
}
|
|
1600
|
+
),
|
|
1601
|
+
open && suggestions.length > 0 && /* @__PURE__ */ jsx5(
|
|
1602
|
+
"div",
|
|
1603
|
+
{
|
|
1604
|
+
ref: listRef,
|
|
1605
|
+
style: {
|
|
1606
|
+
position: "absolute",
|
|
1607
|
+
top: "calc(100% + 4px)",
|
|
1608
|
+
left: -32,
|
|
1609
|
+
right: 0,
|
|
1610
|
+
zIndex: 50,
|
|
1611
|
+
maxHeight: DROPDOWN_MAX_HEIGHT2,
|
|
1612
|
+
overflowY: "auto",
|
|
1613
|
+
backgroundColor: "var(--vj-bg-panel, #252526)",
|
|
1614
|
+
border: "1px solid var(--vj-border, #333333)",
|
|
1615
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.3)"
|
|
1616
|
+
},
|
|
1617
|
+
children: suggestions.map((s, i) => /* @__PURE__ */ jsxs3(
|
|
1618
|
+
"div",
|
|
1619
|
+
{
|
|
1620
|
+
onMouseDown: (e) => {
|
|
1621
|
+
e.preventDefault();
|
|
1622
|
+
selectValue(s);
|
|
1623
|
+
},
|
|
1624
|
+
onMouseEnter: () => setHighlightIndex(i),
|
|
1625
|
+
style: {
|
|
1626
|
+
padding: "4px 12px",
|
|
1627
|
+
fontSize: 13,
|
|
1628
|
+
fontFamily: "var(--vj-font, monospace)",
|
|
1629
|
+
display: "flex",
|
|
1630
|
+
alignItems: "center",
|
|
1631
|
+
gap: 6,
|
|
1632
|
+
color: i === highlightIndex ? "var(--vj-text, #cccccc)" : "var(--vj-text-muted, #888888)",
|
|
1633
|
+
backgroundColor: i === highlightIndex ? "var(--vj-bg-hover, #2a2d2e)" : "transparent",
|
|
1634
|
+
cursor: "pointer",
|
|
1635
|
+
whiteSpace: "nowrap",
|
|
1636
|
+
overflow: "hidden",
|
|
1637
|
+
textOverflow: "ellipsis"
|
|
1638
|
+
},
|
|
1639
|
+
children: [
|
|
1640
|
+
/* @__PURE__ */ jsx5("span", { style: { width: 14, flexShrink: 0, fontSize: 12 }, children: s === value ? "\u2713" : "" }),
|
|
1641
|
+
s
|
|
1642
|
+
]
|
|
1643
|
+
},
|
|
1644
|
+
s
|
|
1645
|
+
))
|
|
1646
|
+
}
|
|
1647
|
+
)
|
|
1648
|
+
]
|
|
1649
|
+
}
|
|
1650
|
+
);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
// src/form-view.tsx
|
|
1654
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1655
|
+
function getResolvedSchema(schema, rootSchema, path) {
|
|
1656
|
+
if (!schema) return void 0;
|
|
1657
|
+
const raw = getPropertySchema(schema, path, rootSchema);
|
|
1658
|
+
if (!raw) return void 0;
|
|
1659
|
+
return resolveRef(raw, rootSchema ?? schema);
|
|
1660
|
+
}
|
|
1661
|
+
function getValueColor(node) {
|
|
1662
|
+
if (node.type === "boolean" || node.type === "null")
|
|
1663
|
+
return "var(--vj-boolean, #569cd6)";
|
|
1664
|
+
if (node.type === "number") return "var(--vj-number, #b5cea8)";
|
|
1665
|
+
return "var(--vj-string, #ce9178)";
|
|
1666
|
+
}
|
|
1667
|
+
function getDisplayValue(node) {
|
|
1668
|
+
if (node.type === "null") return "null";
|
|
1669
|
+
if (node.type === "boolean") return String(node.value);
|
|
1670
|
+
if (node.value === null || node.value === void 0) return "";
|
|
1671
|
+
return String(node.value);
|
|
1672
|
+
}
|
|
1673
|
+
function FormField({
|
|
1674
|
+
node,
|
|
1675
|
+
schema,
|
|
1676
|
+
rootSchema,
|
|
1677
|
+
depth,
|
|
1678
|
+
showDescriptions,
|
|
1679
|
+
showCounts,
|
|
1680
|
+
editingNodeId,
|
|
1681
|
+
collapsedIds,
|
|
1682
|
+
maxKeyLength,
|
|
1683
|
+
maxDepth,
|
|
1684
|
+
isFocused,
|
|
1685
|
+
dragState,
|
|
1686
|
+
onSelect,
|
|
1687
|
+
onToggleCollapse,
|
|
1688
|
+
onStartEditing,
|
|
1689
|
+
onDragStart,
|
|
1690
|
+
onDragOver,
|
|
1691
|
+
onDragEnd,
|
|
1692
|
+
onDrop
|
|
1693
|
+
}) {
|
|
1694
|
+
const { state, actions } = useStudio();
|
|
1695
|
+
const isContainer = node.type === "object" || node.type === "array";
|
|
1696
|
+
const collapsed = collapsedIds.has(node.id);
|
|
1697
|
+
const isSelected = state.selectedNodeIds.has(node.id);
|
|
1698
|
+
const isEditing = editingNodeId === node.id;
|
|
1699
|
+
const propSchema = getResolvedSchema(schema, rootSchema, node.path);
|
|
1700
|
+
const isRequired = checkRequired(node, schema, rootSchema);
|
|
1701
|
+
const [hovered, setHovered] = useState7(false);
|
|
1702
|
+
const isRoot = node.parentId === null;
|
|
1703
|
+
const isDragTarget = dragState.dropTargetNodeId === node.id;
|
|
1704
|
+
const isDraggedNode = dragState.draggedNodeIds.has(node.id);
|
|
1705
|
+
function handleDragOverEvent(e) {
|
|
1706
|
+
e.preventDefault();
|
|
1707
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
1708
|
+
const midY = rect.top + rect.height / 2;
|
|
1709
|
+
onDragOver(node.id, e.clientY < midY ? "before" : "after");
|
|
1710
|
+
}
|
|
1711
|
+
let borderTopColor = "transparent";
|
|
1712
|
+
let borderBottomColor = "transparent";
|
|
1713
|
+
if (isDragTarget && dragState.dropPosition === "before") {
|
|
1714
|
+
borderTopColor = "var(--vj-accent, #007acc)";
|
|
1715
|
+
} else if (isDragTarget && dragState.dropPosition === "after") {
|
|
1716
|
+
borderBottomColor = "var(--vj-accent, #007acc)";
|
|
1717
|
+
}
|
|
1718
|
+
const valueRef = useRef7(null);
|
|
1719
|
+
const keyRef = useRef7(null);
|
|
1720
|
+
useEffect6(() => {
|
|
1721
|
+
if (!isEditing) return;
|
|
1722
|
+
if (!isContainer) {
|
|
1723
|
+
const hasValue = node.value !== null && node.value !== void 0 && node.value !== "";
|
|
1724
|
+
if (hasValue && valueRef.current) {
|
|
1725
|
+
valueRef.current.focus();
|
|
1726
|
+
} else if (keyRef.current) {
|
|
1727
|
+
keyRef.current.focus();
|
|
1197
1728
|
}
|
|
1198
1729
|
} else if (keyRef.current) {
|
|
1199
1730
|
keyRef.current.focus();
|
|
1200
1731
|
}
|
|
1201
1732
|
}, [isEditing, isContainer, node.value]);
|
|
1202
|
-
const handleValueChange =
|
|
1733
|
+
const handleValueChange = useCallback6(
|
|
1203
1734
|
(newValue) => {
|
|
1204
1735
|
let parsed;
|
|
1205
1736
|
if (propSchema?.type === "boolean" || newValue === "true" || newValue === "false") {
|
|
@@ -1217,38 +1748,40 @@ function FormField({
|
|
|
1217
1748
|
},
|
|
1218
1749
|
[state.tree, node.id, node.type, actions, propSchema]
|
|
1219
1750
|
);
|
|
1220
|
-
const handleKeyChange =
|
|
1751
|
+
const handleKeyChange = useCallback6(
|
|
1221
1752
|
(newKey) => {
|
|
1222
1753
|
const newTree = setKey(state.tree, node.id, newKey);
|
|
1223
1754
|
actions.setTree(newTree);
|
|
1224
1755
|
},
|
|
1225
1756
|
[state.tree, node.id, actions]
|
|
1226
1757
|
);
|
|
1227
|
-
const handleRemove =
|
|
1228
|
-
const newTree =
|
|
1758
|
+
const handleRemove = useCallback6(() => {
|
|
1759
|
+
const newTree = removeNode4(state.tree, node.id);
|
|
1229
1760
|
actions.setTree(newTree);
|
|
1230
1761
|
}, [state.tree, node.id, actions]);
|
|
1231
|
-
const handleAddChild =
|
|
1762
|
+
const handleAddChild = useCallback6(() => {
|
|
1232
1763
|
const key = node.type === "array" ? String(node.children.length) : `newKey${node.children.length}`;
|
|
1233
1764
|
const newTree = addProperty(state.tree, node.id, key, "");
|
|
1234
1765
|
actions.setTree(newTree);
|
|
1235
1766
|
}, [state.tree, node.id, node.type, node.children.length, actions]);
|
|
1236
1767
|
const description = propSchema?.description;
|
|
1237
|
-
const defaultVal = propSchema?.default;
|
|
1238
1768
|
const isDeprecated = propSchema?.deprecated;
|
|
1239
1769
|
const fieldTitle = propSchema?.title;
|
|
1240
1770
|
const parentIsObject = node.parentId && state.tree.nodesById.get(node.parentId)?.type === "object";
|
|
1241
1771
|
const rowBg = isSelected ? isFocused ? "var(--vj-bg-selected, #2a5a1e)" : "var(--vj-bg-selected-muted, var(--vj-bg-hover, #2a2d2e))" : hovered ? "var(--vj-bg-hover, #2a2d2e)" : "transparent";
|
|
1242
1772
|
const rowColor = isSelected && isFocused ? "var(--vj-text-selected, var(--vj-text, #cccccc))" : "var(--vj-text, #cccccc)";
|
|
1243
1773
|
if (isContainer) {
|
|
1244
|
-
return /* @__PURE__ */
|
|
1245
|
-
/* @__PURE__ */
|
|
1774
|
+
return /* @__PURE__ */ jsxs4("div", { children: [
|
|
1775
|
+
/* @__PURE__ */ jsxs4(
|
|
1246
1776
|
"div",
|
|
1247
1777
|
{
|
|
1248
1778
|
"data-form-node-id": node.id,
|
|
1249
1779
|
draggable: !isRoot,
|
|
1250
1780
|
onDragStart: (e) => {
|
|
1251
1781
|
e.dataTransfer.effectAllowed = "move";
|
|
1782
|
+
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
1783
|
+
setMultiDragImage(e, state.selectedNodeIds.size);
|
|
1784
|
+
}
|
|
1252
1785
|
onDragStart(node.id);
|
|
1253
1786
|
},
|
|
1254
1787
|
onDragOver: handleDragOverEvent,
|
|
@@ -1261,26 +1794,27 @@ function FormField({
|
|
|
1261
1794
|
display: "flex",
|
|
1262
1795
|
alignItems: "center",
|
|
1263
1796
|
gap: 6,
|
|
1264
|
-
padding: "
|
|
1797
|
+
padding: "1px 8px",
|
|
1265
1798
|
paddingLeft: 8 + depth * 16,
|
|
1266
1799
|
cursor: "pointer",
|
|
1267
1800
|
backgroundColor: rowBg,
|
|
1268
1801
|
color: rowColor,
|
|
1269
1802
|
height: 28,
|
|
1803
|
+
boxSizing: "border-box",
|
|
1270
1804
|
userSelect: "none",
|
|
1271
1805
|
opacity: isDeprecated ? 0.5 : isDraggedNode ? 0.4 : 1,
|
|
1272
|
-
borderTop
|
|
1273
|
-
borderBottom
|
|
1806
|
+
borderTop: `2px solid ${borderTopColor}`,
|
|
1807
|
+
borderBottom: `2px solid ${borderBottomColor}`
|
|
1274
1808
|
},
|
|
1275
1809
|
onClick: (e) => {
|
|
1276
1810
|
e.stopPropagation();
|
|
1277
|
-
onSelect(node.id);
|
|
1811
|
+
onSelect(node.id, e);
|
|
1278
1812
|
},
|
|
1279
1813
|
onDoubleClick: () => onToggleCollapse(node.id),
|
|
1280
1814
|
onMouseEnter: () => setHovered(true),
|
|
1281
1815
|
onMouseLeave: () => setHovered(false),
|
|
1282
1816
|
children: [
|
|
1283
|
-
/* @__PURE__ */
|
|
1817
|
+
/* @__PURE__ */ jsx6(
|
|
1284
1818
|
"button",
|
|
1285
1819
|
{
|
|
1286
1820
|
onClick: (e) => {
|
|
@@ -1305,7 +1839,7 @@ function FormField({
|
|
|
1305
1839
|
children: "\u25B6"
|
|
1306
1840
|
}
|
|
1307
1841
|
),
|
|
1308
|
-
isEditing && !isRoot ? /* @__PURE__ */
|
|
1842
|
+
isEditing && !isRoot ? /* @__PURE__ */ jsx6(
|
|
1309
1843
|
"input",
|
|
1310
1844
|
{
|
|
1311
1845
|
ref: keyRef,
|
|
@@ -1317,7 +1851,7 @@ function FormField({
|
|
|
1317
1851
|
border: "none",
|
|
1318
1852
|
color: "inherit",
|
|
1319
1853
|
fontFamily: "var(--vj-font, monospace)",
|
|
1320
|
-
fontSize:
|
|
1854
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1321
1855
|
fontWeight: 500,
|
|
1322
1856
|
padding: 0,
|
|
1323
1857
|
outline: "none",
|
|
@@ -1325,12 +1859,12 @@ function FormField({
|
|
|
1325
1859
|
width: `calc(${(maxDepth - depth) * 16}px + ${maxKeyLength}ch)`
|
|
1326
1860
|
}
|
|
1327
1861
|
}
|
|
1328
|
-
) : /* @__PURE__ */
|
|
1862
|
+
) : /* @__PURE__ */ jsx6(
|
|
1329
1863
|
"span",
|
|
1330
1864
|
{
|
|
1331
1865
|
style: {
|
|
1332
1866
|
color: !isRoot && !parentIsObject && !isSelected ? "var(--vj-text-muted, #888888)" : "inherit",
|
|
1333
|
-
fontSize:
|
|
1867
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1334
1868
|
fontFamily: "var(--vj-font, monospace)",
|
|
1335
1869
|
fontWeight: 500,
|
|
1336
1870
|
flexShrink: 0,
|
|
@@ -1340,7 +1874,7 @@ function FormField({
|
|
|
1340
1874
|
children: isRoot ? "/" : getDisplayKey(node, state.tree)
|
|
1341
1875
|
}
|
|
1342
1876
|
),
|
|
1343
|
-
showDescriptions && fieldTitle && !isSelected && /* @__PURE__ */
|
|
1877
|
+
showDescriptions && fieldTitle && !isSelected && /* @__PURE__ */ jsx6(
|
|
1344
1878
|
"span",
|
|
1345
1879
|
{
|
|
1346
1880
|
style: {
|
|
@@ -1351,7 +1885,7 @@ function FormField({
|
|
|
1351
1885
|
children: fieldTitle
|
|
1352
1886
|
}
|
|
1353
1887
|
),
|
|
1354
|
-
hovered && /* @__PURE__ */
|
|
1888
|
+
hovered && /* @__PURE__ */ jsxs4(
|
|
1355
1889
|
"button",
|
|
1356
1890
|
{
|
|
1357
1891
|
onClick: (e) => {
|
|
@@ -1373,7 +1907,7 @@ function FormField({
|
|
|
1373
1907
|
]
|
|
1374
1908
|
}
|
|
1375
1909
|
),
|
|
1376
|
-
showCounts && /* @__PURE__ */
|
|
1910
|
+
showCounts && /* @__PURE__ */ jsx6(
|
|
1377
1911
|
"span",
|
|
1378
1912
|
{
|
|
1379
1913
|
style: {
|
|
@@ -1385,7 +1919,7 @@ function FormField({
|
|
|
1385
1919
|
children: node.type === "array" ? `${node.children.length} items` : `${node.children.length} properties`
|
|
1386
1920
|
}
|
|
1387
1921
|
),
|
|
1388
|
-
!isRoot && isEditing && /* @__PURE__ */
|
|
1922
|
+
!isRoot && isEditing && /* @__PURE__ */ jsx6(
|
|
1389
1923
|
"button",
|
|
1390
1924
|
{
|
|
1391
1925
|
onClick: (e) => {
|
|
@@ -1409,7 +1943,7 @@ function FormField({
|
|
|
1409
1943
|
]
|
|
1410
1944
|
}
|
|
1411
1945
|
),
|
|
1412
|
-
showDescriptions && description && /* @__PURE__ */
|
|
1946
|
+
showDescriptions && description && /* @__PURE__ */ jsx6(
|
|
1413
1947
|
"div",
|
|
1414
1948
|
{
|
|
1415
1949
|
style: {
|
|
@@ -1422,7 +1956,7 @@ function FormField({
|
|
|
1422
1956
|
children: description
|
|
1423
1957
|
}
|
|
1424
1958
|
),
|
|
1425
|
-
!collapsed && /* @__PURE__ */
|
|
1959
|
+
!collapsed && /* @__PURE__ */ jsx6("div", { children: node.children.map((child) => /* @__PURE__ */ jsx6(
|
|
1426
1960
|
FormField,
|
|
1427
1961
|
{
|
|
1428
1962
|
node: child,
|
|
@@ -1431,7 +1965,6 @@ function FormField({
|
|
|
1431
1965
|
depth: depth + 1,
|
|
1432
1966
|
showDescriptions,
|
|
1433
1967
|
showCounts,
|
|
1434
|
-
formSelectedNodeId,
|
|
1435
1968
|
editingNodeId,
|
|
1436
1969
|
collapsedIds,
|
|
1437
1970
|
maxKeyLength,
|
|
@@ -1452,13 +1985,16 @@ function FormField({
|
|
|
1452
1985
|
}
|
|
1453
1986
|
const displayValue = getDisplayValue(node);
|
|
1454
1987
|
const valueColor = getValueColor(node);
|
|
1455
|
-
return /* @__PURE__ */
|
|
1988
|
+
return /* @__PURE__ */ jsxs4(
|
|
1456
1989
|
"div",
|
|
1457
1990
|
{
|
|
1458
1991
|
"data-form-node-id": node.id,
|
|
1459
1992
|
draggable: !isRoot,
|
|
1460
1993
|
onDragStart: (e) => {
|
|
1461
1994
|
e.dataTransfer.effectAllowed = "move";
|
|
1995
|
+
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
1996
|
+
setMultiDragImage(e, state.selectedNodeIds.size);
|
|
1997
|
+
}
|
|
1462
1998
|
onDragStart(node.id);
|
|
1463
1999
|
},
|
|
1464
2000
|
onDragOver: handleDragOverEvent,
|
|
@@ -1471,27 +2007,28 @@ function FormField({
|
|
|
1471
2007
|
display: "flex",
|
|
1472
2008
|
alignItems: "center",
|
|
1473
2009
|
gap: 6,
|
|
1474
|
-
padding: "
|
|
2010
|
+
padding: "1px 8px",
|
|
1475
2011
|
paddingLeft: 8 + depth * 16,
|
|
1476
2012
|
cursor: "pointer",
|
|
1477
2013
|
backgroundColor: rowBg,
|
|
1478
2014
|
color: rowColor,
|
|
1479
2015
|
height: 28,
|
|
2016
|
+
boxSizing: "border-box",
|
|
1480
2017
|
userSelect: "none",
|
|
1481
2018
|
opacity: isDeprecated ? 0.5 : isDraggedNode ? 0.4 : 1,
|
|
1482
|
-
borderTop
|
|
1483
|
-
borderBottom
|
|
2019
|
+
borderTop: `2px solid ${borderTopColor}`,
|
|
2020
|
+
borderBottom: `2px solid ${borderBottomColor}`
|
|
1484
2021
|
},
|
|
1485
2022
|
onClick: (e) => {
|
|
1486
2023
|
e.stopPropagation();
|
|
1487
|
-
onSelect(node.id);
|
|
2024
|
+
onSelect(node.id, e);
|
|
1488
2025
|
},
|
|
1489
2026
|
onDoubleClick: () => onStartEditing(node.id),
|
|
1490
2027
|
onMouseEnter: () => setHovered(true),
|
|
1491
2028
|
onMouseLeave: () => setHovered(false),
|
|
1492
2029
|
children: [
|
|
1493
|
-
/* @__PURE__ */
|
|
1494
|
-
isEditing && parentIsObject ? /* @__PURE__ */
|
|
2030
|
+
/* @__PURE__ */ jsx6("span", { style: { width: 16, flexShrink: 0 } }),
|
|
2031
|
+
isEditing && parentIsObject ? /* @__PURE__ */ jsx6(
|
|
1495
2032
|
"input",
|
|
1496
2033
|
{
|
|
1497
2034
|
ref: keyRef,
|
|
@@ -1509,19 +2046,19 @@ function FormField({
|
|
|
1509
2046
|
border: "none",
|
|
1510
2047
|
color: "inherit",
|
|
1511
2048
|
fontFamily: "var(--vj-font, monospace)",
|
|
1512
|
-
fontSize:
|
|
2049
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1513
2050
|
padding: 0,
|
|
1514
2051
|
flexShrink: 0,
|
|
1515
2052
|
outline: "none",
|
|
1516
2053
|
width: `calc(${(maxDepth - depth) * 16}px + ${maxKeyLength}ch)`
|
|
1517
2054
|
}
|
|
1518
2055
|
}
|
|
1519
|
-
) : /* @__PURE__ */
|
|
2056
|
+
) : /* @__PURE__ */ jsx6(
|
|
1520
2057
|
"span",
|
|
1521
2058
|
{
|
|
1522
2059
|
style: {
|
|
1523
2060
|
color: !parentIsObject && !isSelected ? "var(--vj-text-muted, #888888)" : "inherit",
|
|
1524
|
-
fontSize:
|
|
2061
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1525
2062
|
fontFamily: "var(--vj-font, monospace)",
|
|
1526
2063
|
flexShrink: 0,
|
|
1527
2064
|
display: "inline-block",
|
|
@@ -1530,7 +2067,7 @@ function FormField({
|
|
|
1530
2067
|
children: getDisplayKey(node, state.tree)
|
|
1531
2068
|
}
|
|
1532
2069
|
),
|
|
1533
|
-
isRequired && !isSelected && /* @__PURE__ */
|
|
2070
|
+
isRequired && !isSelected && /* @__PURE__ */ jsx6(
|
|
1534
2071
|
"span",
|
|
1535
2072
|
{
|
|
1536
2073
|
style: {
|
|
@@ -1541,7 +2078,7 @@ function FormField({
|
|
|
1541
2078
|
children: "*"
|
|
1542
2079
|
}
|
|
1543
2080
|
),
|
|
1544
|
-
isEditing ? /* @__PURE__ */
|
|
2081
|
+
isEditing ? /* @__PURE__ */ jsx6(
|
|
1545
2082
|
"div",
|
|
1546
2083
|
{
|
|
1547
2084
|
style: {
|
|
@@ -1560,12 +2097,12 @@ function FormField({
|
|
|
1560
2097
|
valueColor
|
|
1561
2098
|
)
|
|
1562
2099
|
}
|
|
1563
|
-
) : /* @__PURE__ */
|
|
2100
|
+
) : /* @__PURE__ */ jsx6(
|
|
1564
2101
|
"span",
|
|
1565
2102
|
{
|
|
1566
2103
|
style: {
|
|
1567
2104
|
color: valueColor,
|
|
1568
|
-
fontSize:
|
|
2105
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1569
2106
|
fontFamily: "var(--vj-font, monospace)",
|
|
1570
2107
|
overflow: "hidden",
|
|
1571
2108
|
textOverflow: "ellipsis",
|
|
@@ -1575,7 +2112,7 @@ function FormField({
|
|
|
1575
2112
|
children: displayValue
|
|
1576
2113
|
}
|
|
1577
2114
|
),
|
|
1578
|
-
isEditing && /* @__PURE__ */
|
|
2115
|
+
isEditing && /* @__PURE__ */ jsx6(
|
|
1579
2116
|
"button",
|
|
1580
2117
|
{
|
|
1581
2118
|
onClick: (e) => {
|
|
@@ -1606,54 +2143,44 @@ function renderEditInput(node, propSchema, displayValue, handleValueChange, inpu
|
|
|
1606
2143
|
background: "none",
|
|
1607
2144
|
border: "none",
|
|
1608
2145
|
fontFamily: "var(--vj-font, monospace)",
|
|
1609
|
-
fontSize:
|
|
2146
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1610
2147
|
padding: 0,
|
|
1611
2148
|
flex: 1,
|
|
1612
2149
|
outline: "none",
|
|
1613
2150
|
color: valueColor
|
|
1614
2151
|
};
|
|
1615
2152
|
if (node.type === "boolean") {
|
|
1616
|
-
return /* @__PURE__ */
|
|
1617
|
-
|
|
2153
|
+
return /* @__PURE__ */ jsx6(
|
|
2154
|
+
EnumInput,
|
|
1618
2155
|
{
|
|
1619
|
-
|
|
2156
|
+
enumValues: ["true", "false"],
|
|
1620
2157
|
value: String(node.value),
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
children: [
|
|
1625
|
-
/* @__PURE__ */ jsx5("option", { value: "true", children: "true" }),
|
|
1626
|
-
/* @__PURE__ */ jsx5("option", { value: "false", children: "false" })
|
|
1627
|
-
]
|
|
2158
|
+
onValueChange: handleValueChange,
|
|
2159
|
+
inputRef,
|
|
2160
|
+
inputStyle
|
|
1628
2161
|
}
|
|
1629
2162
|
);
|
|
1630
2163
|
}
|
|
1631
2164
|
if (hasEnumValues && propSchema?.enum) {
|
|
1632
|
-
return /* @__PURE__ */
|
|
1633
|
-
|
|
2165
|
+
return /* @__PURE__ */ jsx6(
|
|
2166
|
+
EnumInput,
|
|
1634
2167
|
{
|
|
1635
|
-
|
|
2168
|
+
enumValues: propSchema.enum,
|
|
1636
2169
|
value: displayValue,
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
children: [
|
|
1641
|
-
!propSchema.enum.some(
|
|
1642
|
-
(v) => JSON.stringify(v) === JSON.stringify(node.value)
|
|
1643
|
-
) && /* @__PURE__ */ jsx5("option", { value: displayValue, children: displayValue || "(empty)" }),
|
|
1644
|
-
propSchema.enum.map((v, i) => /* @__PURE__ */ jsx5("option", { value: String(v), children: String(v) }, i))
|
|
1645
|
-
]
|
|
2170
|
+
onValueChange: handleValueChange,
|
|
2171
|
+
inputRef,
|
|
2172
|
+
inputStyle
|
|
1646
2173
|
}
|
|
1647
2174
|
);
|
|
1648
2175
|
}
|
|
1649
2176
|
if (node.type === "null") {
|
|
1650
|
-
return /* @__PURE__ */
|
|
2177
|
+
return /* @__PURE__ */ jsx6(
|
|
1651
2178
|
"span",
|
|
1652
2179
|
{
|
|
1653
2180
|
style: {
|
|
1654
2181
|
color: "var(--vj-boolean, #569cd6)",
|
|
1655
2182
|
fontFamily: "var(--vj-font, monospace)",
|
|
1656
|
-
fontSize:
|
|
2183
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
1657
2184
|
fontStyle: "italic",
|
|
1658
2185
|
flex: 1
|
|
1659
2186
|
},
|
|
@@ -1661,7 +2188,7 @@ function renderEditInput(node, propSchema, displayValue, handleValueChange, inpu
|
|
|
1661
2188
|
}
|
|
1662
2189
|
);
|
|
1663
2190
|
}
|
|
1664
|
-
return /* @__PURE__ */
|
|
2191
|
+
return /* @__PURE__ */ jsx6(
|
|
1665
2192
|
"input",
|
|
1666
2193
|
{
|
|
1667
2194
|
ref: inputRef,
|
|
@@ -1686,35 +2213,35 @@ function FormView({
|
|
|
1686
2213
|
}) {
|
|
1687
2214
|
const { state, actions } = useStudio();
|
|
1688
2215
|
const rootSchema = state.schema ?? void 0;
|
|
1689
|
-
const
|
|
1690
|
-
const displayNode =
|
|
1691
|
-
const [
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
const [editingNodeId, setEditingNodeId] = useState6(null);
|
|
1695
|
-
const preEditTreeRef = useRef6(null);
|
|
1696
|
-
const [collapsedIds, setCollapsedIds] = useState6(
|
|
2216
|
+
const drillDownNode = state.drillDownNodeId ? state.tree.nodesById.get(state.drillDownNodeId) : null;
|
|
2217
|
+
const displayNode = drillDownNode ?? state.tree.root;
|
|
2218
|
+
const [editingNodeId, setEditingNodeId] = useState7(null);
|
|
2219
|
+
const preEditTreeRef = useRef7(null);
|
|
2220
|
+
const [collapsedIds, setCollapsedIds] = useState7(
|
|
1697
2221
|
() => /* @__PURE__ */ new Set()
|
|
1698
2222
|
);
|
|
1699
|
-
const containerRef =
|
|
1700
|
-
const [isFocused, setIsFocused] =
|
|
1701
|
-
|
|
1702
|
-
dragState,
|
|
1703
|
-
handleDragStart,
|
|
1704
|
-
handleDragOver,
|
|
1705
|
-
handleDragEnd,
|
|
1706
|
-
handleDrop
|
|
1707
|
-
} = useDragDrop();
|
|
1708
|
-
useEffect5(() => {
|
|
1709
|
-
setFormSelectedNodeId(null);
|
|
2223
|
+
const containerRef = useRef7(null);
|
|
2224
|
+
const [isFocused, setIsFocused] = useState7(false);
|
|
2225
|
+
useEffect6(() => {
|
|
1710
2226
|
setEditingNodeId(null);
|
|
1711
2227
|
setCollapsedIds(/* @__PURE__ */ new Set());
|
|
1712
2228
|
}, [displayNode.id]);
|
|
1713
|
-
const visibleNodes =
|
|
2229
|
+
const visibleNodes = useMemo6(
|
|
1714
2230
|
() => getVisibleNodes(displayNode, (id) => !collapsedIds.has(id)),
|
|
1715
2231
|
[displayNode, collapsedIds]
|
|
1716
2232
|
);
|
|
1717
|
-
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(() => {
|
|
1718
2245
|
let maxKey = 1;
|
|
1719
2246
|
let maxD = 0;
|
|
1720
2247
|
const baseSegments = displayNode.path === "/" ? 0 : displayNode.path.split("/").filter(Boolean).length;
|
|
@@ -1727,11 +2254,21 @@ function FormView({
|
|
|
1727
2254
|
}
|
|
1728
2255
|
return { maxKeyLength: maxKey, maxDepth: maxD };
|
|
1729
2256
|
}, [visibleNodes, displayNode.path, state.tree]);
|
|
1730
|
-
const handleSelect =
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
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
|
+
);
|
|
2271
|
+
const handleToggleCollapse = useCallback6((nodeId) => {
|
|
1735
2272
|
setCollapsedIds((prev) => {
|
|
1736
2273
|
const next = new Set(prev);
|
|
1737
2274
|
if (next.has(nodeId)) {
|
|
@@ -1742,14 +2279,14 @@ function FormView({
|
|
|
1742
2279
|
return next;
|
|
1743
2280
|
});
|
|
1744
2281
|
}, []);
|
|
1745
|
-
const handleStartEditing =
|
|
2282
|
+
const handleStartEditing = useCallback6(
|
|
1746
2283
|
(nodeId) => {
|
|
1747
2284
|
preEditTreeRef.current = state.tree;
|
|
1748
2285
|
setEditingNodeId(nodeId);
|
|
1749
2286
|
},
|
|
1750
2287
|
[state.tree]
|
|
1751
2288
|
);
|
|
1752
|
-
const scrollToNode =
|
|
2289
|
+
const scrollToNode = useCallback6((nodeId) => {
|
|
1753
2290
|
requestAnimationFrame(() => {
|
|
1754
2291
|
const el = containerRef.current?.querySelector(
|
|
1755
2292
|
`[data-form-node-id="${nodeId}"]`
|
|
@@ -1757,7 +2294,7 @@ function FormView({
|
|
|
1757
2294
|
el?.scrollIntoView({ block: "nearest" });
|
|
1758
2295
|
});
|
|
1759
2296
|
}, []);
|
|
1760
|
-
const handleKeyDown =
|
|
2297
|
+
const handleKeyDown = useCallback6(
|
|
1761
2298
|
(e) => {
|
|
1762
2299
|
if (editingNodeId) {
|
|
1763
2300
|
if (e.key === "Escape") {
|
|
@@ -1778,15 +2315,23 @@ function FormView({
|
|
|
1778
2315
|
}
|
|
1779
2316
|
return;
|
|
1780
2317
|
}
|
|
1781
|
-
|
|
1782
|
-
(n) => n.id ===
|
|
2318
|
+
let currentIndex = visibleNodes.findIndex(
|
|
2319
|
+
(n) => n.id === state.focusedNodeId
|
|
1783
2320
|
);
|
|
2321
|
+
if (currentIndex === -1 && visibleNodes.length > 0) {
|
|
2322
|
+
currentIndex = 0;
|
|
2323
|
+
}
|
|
1784
2324
|
switch (e.key) {
|
|
1785
2325
|
case "ArrowDown": {
|
|
1786
2326
|
e.preventDefault();
|
|
1787
2327
|
const next = visibleNodes[currentIndex + 1];
|
|
1788
2328
|
if (next) {
|
|
1789
|
-
|
|
2329
|
+
if (e.shiftKey) {
|
|
2330
|
+
actions.setVisibleNodesOverride(visibleNodes);
|
|
2331
|
+
actions.selectNodeRange(next.id);
|
|
2332
|
+
} else {
|
|
2333
|
+
actions.selectNode(next.id);
|
|
2334
|
+
}
|
|
1790
2335
|
scrollToNode(next.id);
|
|
1791
2336
|
}
|
|
1792
2337
|
break;
|
|
@@ -1795,7 +2340,12 @@ function FormView({
|
|
|
1795
2340
|
e.preventDefault();
|
|
1796
2341
|
const prev = visibleNodes[currentIndex - 1];
|
|
1797
2342
|
if (prev) {
|
|
1798
|
-
|
|
2343
|
+
if (e.shiftKey) {
|
|
2344
|
+
actions.setVisibleNodesOverride(visibleNodes);
|
|
2345
|
+
actions.selectNodeRange(prev.id);
|
|
2346
|
+
} else {
|
|
2347
|
+
actions.selectNode(prev.id);
|
|
2348
|
+
}
|
|
1799
2349
|
scrollToNode(prev.id);
|
|
1800
2350
|
}
|
|
1801
2351
|
break;
|
|
@@ -1811,7 +2361,7 @@ function FormView({
|
|
|
1811
2361
|
return next;
|
|
1812
2362
|
});
|
|
1813
2363
|
} else if (node.children.length > 0) {
|
|
1814
|
-
|
|
2364
|
+
actions.selectNode(node.children[0].id);
|
|
1815
2365
|
scrollToNode(node.children[0].id);
|
|
1816
2366
|
}
|
|
1817
2367
|
}
|
|
@@ -1833,7 +2383,7 @@ function FormView({
|
|
|
1833
2383
|
(n) => n.id === current.parentId
|
|
1834
2384
|
);
|
|
1835
2385
|
if (parentInVisible) {
|
|
1836
|
-
|
|
2386
|
+
actions.selectNode(parentInVisible.id);
|
|
1837
2387
|
scrollToNode(parentInVisible.id);
|
|
1838
2388
|
}
|
|
1839
2389
|
}
|
|
@@ -1841,30 +2391,54 @@ function FormView({
|
|
|
1841
2391
|
}
|
|
1842
2392
|
case "Enter": {
|
|
1843
2393
|
e.preventDefault();
|
|
1844
|
-
if (
|
|
2394
|
+
if (state.focusedNodeId) {
|
|
1845
2395
|
preEditTreeRef.current = state.tree;
|
|
1846
|
-
|
|
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
|
+
}
|
|
1847
2416
|
}
|
|
1848
2417
|
break;
|
|
1849
2418
|
}
|
|
1850
2419
|
case "Escape": {
|
|
1851
2420
|
e.preventDefault();
|
|
1852
|
-
|
|
2421
|
+
if (state.selectedNodeIds.size > 1 && state.focusedNodeId) {
|
|
2422
|
+
actions.selectNode(state.focusedNodeId);
|
|
2423
|
+
} else {
|
|
2424
|
+
actions.setSelection(null, /* @__PURE__ */ new Set(), null);
|
|
2425
|
+
}
|
|
1853
2426
|
break;
|
|
1854
2427
|
}
|
|
1855
2428
|
case "Delete":
|
|
1856
2429
|
case "Backspace": {
|
|
1857
2430
|
e.preventDefault();
|
|
1858
|
-
const
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
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);
|
|
1868
2442
|
}
|
|
1869
2443
|
break;
|
|
1870
2444
|
}
|
|
@@ -1872,7 +2446,8 @@ function FormView({
|
|
|
1872
2446
|
},
|
|
1873
2447
|
[
|
|
1874
2448
|
visibleNodes,
|
|
1875
|
-
|
|
2449
|
+
state.focusedNodeId,
|
|
2450
|
+
state.selectedNodeIds,
|
|
1876
2451
|
editingNodeId,
|
|
1877
2452
|
collapsedIds,
|
|
1878
2453
|
scrollToNode,
|
|
@@ -1880,7 +2455,7 @@ function FormView({
|
|
|
1880
2455
|
actions
|
|
1881
2456
|
]
|
|
1882
2457
|
);
|
|
1883
|
-
return /* @__PURE__ */
|
|
2458
|
+
return /* @__PURE__ */ jsxs4(
|
|
1884
2459
|
"div",
|
|
1885
2460
|
{
|
|
1886
2461
|
className,
|
|
@@ -1893,19 +2468,21 @@ function FormView({
|
|
|
1893
2468
|
flexDirection: "column"
|
|
1894
2469
|
},
|
|
1895
2470
|
children: [
|
|
1896
|
-
/* @__PURE__ */
|
|
2471
|
+
/* @__PURE__ */ jsx6(
|
|
1897
2472
|
"div",
|
|
1898
2473
|
{
|
|
1899
2474
|
style: {
|
|
2475
|
+
display: "flex",
|
|
2476
|
+
alignItems: "center",
|
|
1900
2477
|
padding: "4px 8px",
|
|
1901
2478
|
borderBottom: "1px solid var(--vj-border, #333333)",
|
|
1902
|
-
backgroundColor: "var(--vj-bg
|
|
2479
|
+
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
1903
2480
|
flexShrink: 0
|
|
1904
2481
|
},
|
|
1905
|
-
children: /* @__PURE__ */
|
|
2482
|
+
children: /* @__PURE__ */ jsx6(Breadcrumbs, {})
|
|
1906
2483
|
}
|
|
1907
2484
|
),
|
|
1908
|
-
/* @__PURE__ */
|
|
2485
|
+
/* @__PURE__ */ jsx6(
|
|
1909
2486
|
"div",
|
|
1910
2487
|
{
|
|
1911
2488
|
ref: containerRef,
|
|
@@ -1923,7 +2500,7 @@ function FormView({
|
|
|
1923
2500
|
overflow: "auto",
|
|
1924
2501
|
outline: "none"
|
|
1925
2502
|
},
|
|
1926
|
-
children: /* @__PURE__ */
|
|
2503
|
+
children: /* @__PURE__ */ jsx6(
|
|
1927
2504
|
FormField,
|
|
1928
2505
|
{
|
|
1929
2506
|
node: displayNode,
|
|
@@ -1932,7 +2509,6 @@ function FormView({
|
|
|
1932
2509
|
depth: 0,
|
|
1933
2510
|
showDescriptions,
|
|
1934
2511
|
showCounts,
|
|
1935
|
-
formSelectedNodeId,
|
|
1936
2512
|
editingNodeId,
|
|
1937
2513
|
collapsedIds,
|
|
1938
2514
|
maxKeyLength,
|
|
@@ -1956,12 +2532,12 @@ function FormView({
|
|
|
1956
2532
|
}
|
|
1957
2533
|
|
|
1958
2534
|
// src/search-bar.tsx
|
|
1959
|
-
import { useRef as
|
|
1960
|
-
import { Fragment as Fragment2, jsx as
|
|
2535
|
+
import { useRef as useRef8, useEffect as useEffect7, useCallback as useCallback7 } from "react";
|
|
2536
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1961
2537
|
function SearchBar({ className }) {
|
|
1962
2538
|
const { state, actions } = useStudio();
|
|
1963
|
-
const inputRef =
|
|
1964
|
-
const handleKeyDown =
|
|
2539
|
+
const inputRef = useRef8(null);
|
|
2540
|
+
const handleKeyDown = useCallback7(
|
|
1965
2541
|
(e) => {
|
|
1966
2542
|
if (e.key === "Enter") {
|
|
1967
2543
|
e.preventDefault();
|
|
@@ -1979,7 +2555,7 @@ function SearchBar({ className }) {
|
|
|
1979
2555
|
},
|
|
1980
2556
|
[actions]
|
|
1981
2557
|
);
|
|
1982
|
-
|
|
2558
|
+
useEffect7(() => {
|
|
1983
2559
|
function handleGlobalKeyDown(e) {
|
|
1984
2560
|
const mod = e.metaKey || e.ctrlKey;
|
|
1985
2561
|
if (mod && e.key === "f") {
|
|
@@ -1993,7 +2569,7 @@ function SearchBar({ className }) {
|
|
|
1993
2569
|
}, []);
|
|
1994
2570
|
const matchCount = state.searchMatches.length;
|
|
1995
2571
|
const currentMatch = matchCount > 0 ? state.searchMatchIndex + 1 : 0;
|
|
1996
|
-
return /* @__PURE__ */
|
|
2572
|
+
return /* @__PURE__ */ jsxs5(
|
|
1997
2573
|
"div",
|
|
1998
2574
|
{
|
|
1999
2575
|
className,
|
|
@@ -2002,11 +2578,11 @@ function SearchBar({ className }) {
|
|
|
2002
2578
|
alignItems: "center",
|
|
2003
2579
|
gap: 6,
|
|
2004
2580
|
padding: "4px 8px",
|
|
2005
|
-
backgroundColor: "var(--vj-bg
|
|
2581
|
+
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
2006
2582
|
borderBottom: "1px solid var(--vj-border, #333333)"
|
|
2007
2583
|
},
|
|
2008
2584
|
children: [
|
|
2009
|
-
/* @__PURE__ */
|
|
2585
|
+
/* @__PURE__ */ jsx7(
|
|
2010
2586
|
"input",
|
|
2011
2587
|
{
|
|
2012
2588
|
ref: inputRef,
|
|
@@ -2022,14 +2598,14 @@ function SearchBar({ className }) {
|
|
|
2022
2598
|
borderRadius: 3,
|
|
2023
2599
|
color: "var(--vj-text, #cccccc)",
|
|
2024
2600
|
fontFamily: "var(--vj-font, monospace)",
|
|
2025
|
-
fontSize:
|
|
2601
|
+
fontSize: "var(--vj-input-font-size, 13px)",
|
|
2026
2602
|
padding: "3px 8px",
|
|
2027
2603
|
outline: "none",
|
|
2028
2604
|
minWidth: 0
|
|
2029
2605
|
}
|
|
2030
2606
|
}
|
|
2031
2607
|
),
|
|
2032
|
-
/* @__PURE__ */
|
|
2608
|
+
/* @__PURE__ */ jsx7(
|
|
2033
2609
|
"div",
|
|
2034
2610
|
{
|
|
2035
2611
|
style: {
|
|
@@ -2039,8 +2615,8 @@ function SearchBar({ className }) {
|
|
|
2039
2615
|
flexShrink: 0,
|
|
2040
2616
|
height: 18
|
|
2041
2617
|
},
|
|
2042
|
-
children: state.searchQuery ? /* @__PURE__ */
|
|
2043
|
-
/* @__PURE__ */
|
|
2618
|
+
children: state.searchQuery ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2619
|
+
/* @__PURE__ */ jsx7(
|
|
2044
2620
|
"span",
|
|
2045
2621
|
{
|
|
2046
2622
|
style: {
|
|
@@ -2053,7 +2629,7 @@ function SearchBar({ className }) {
|
|
|
2053
2629
|
children: matchCount > 0 ? `${currentMatch}/${matchCount}` : "0/0"
|
|
2054
2630
|
}
|
|
2055
2631
|
),
|
|
2056
|
-
/* @__PURE__ */
|
|
2632
|
+
/* @__PURE__ */ jsx7(
|
|
2057
2633
|
"button",
|
|
2058
2634
|
{
|
|
2059
2635
|
onClick: actions.prevSearchMatch,
|
|
@@ -2077,7 +2653,7 @@ function SearchBar({ className }) {
|
|
|
2077
2653
|
children: "\u25B2"
|
|
2078
2654
|
}
|
|
2079
2655
|
),
|
|
2080
|
-
/* @__PURE__ */
|
|
2656
|
+
/* @__PURE__ */ jsx7(
|
|
2081
2657
|
"button",
|
|
2082
2658
|
{
|
|
2083
2659
|
onClick: actions.nextSearchMatch,
|
|
@@ -2101,7 +2677,7 @@ function SearchBar({ className }) {
|
|
|
2101
2677
|
children: "\u25BC"
|
|
2102
2678
|
}
|
|
2103
2679
|
),
|
|
2104
|
-
/* @__PURE__ */
|
|
2680
|
+
/* @__PURE__ */ jsx7(
|
|
2105
2681
|
"button",
|
|
2106
2682
|
{
|
|
2107
2683
|
onClick: () => actions.setSearchQuery(""),
|
|
@@ -2124,8 +2700,8 @@ function SearchBar({ className }) {
|
|
|
2124
2700
|
children: "\xD7"
|
|
2125
2701
|
}
|
|
2126
2702
|
)
|
|
2127
|
-
] }) : /* @__PURE__ */
|
|
2128
|
-
/* @__PURE__ */
|
|
2703
|
+
] }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2704
|
+
/* @__PURE__ */ jsx7(
|
|
2129
2705
|
"button",
|
|
2130
2706
|
{
|
|
2131
2707
|
onClick: actions.expandAll,
|
|
@@ -2142,7 +2718,7 @@ function SearchBar({ className }) {
|
|
|
2142
2718
|
alignItems: "center"
|
|
2143
2719
|
},
|
|
2144
2720
|
title: "Expand all",
|
|
2145
|
-
children: /* @__PURE__ */
|
|
2721
|
+
children: /* @__PURE__ */ jsxs5(
|
|
2146
2722
|
"svg",
|
|
2147
2723
|
{
|
|
2148
2724
|
width: "14",
|
|
@@ -2154,15 +2730,15 @@ function SearchBar({ className }) {
|
|
|
2154
2730
|
strokeLinecap: "round",
|
|
2155
2731
|
strokeLinejoin: "round",
|
|
2156
2732
|
children: [
|
|
2157
|
-
/* @__PURE__ */
|
|
2158
|
-
/* @__PURE__ */
|
|
2159
|
-
/* @__PURE__ */
|
|
2733
|
+
/* @__PURE__ */ jsx7("path", { d: "M8 2v4M5 4l3-2 3 2" }),
|
|
2734
|
+
/* @__PURE__ */ jsx7("path", { d: "M8 14v-4M5 12l3 2 3-2" }),
|
|
2735
|
+
/* @__PURE__ */ jsx7("path", { d: "M2 8h12" })
|
|
2160
2736
|
]
|
|
2161
2737
|
}
|
|
2162
2738
|
)
|
|
2163
2739
|
}
|
|
2164
2740
|
),
|
|
2165
|
-
/* @__PURE__ */
|
|
2741
|
+
/* @__PURE__ */ jsx7(
|
|
2166
2742
|
"button",
|
|
2167
2743
|
{
|
|
2168
2744
|
onClick: actions.collapseAll,
|
|
@@ -2179,7 +2755,7 @@ function SearchBar({ className }) {
|
|
|
2179
2755
|
alignItems: "center"
|
|
2180
2756
|
},
|
|
2181
2757
|
title: "Collapse all",
|
|
2182
|
-
children: /* @__PURE__ */
|
|
2758
|
+
children: /* @__PURE__ */ jsxs5(
|
|
2183
2759
|
"svg",
|
|
2184
2760
|
{
|
|
2185
2761
|
width: "14",
|
|
@@ -2191,9 +2767,9 @@ function SearchBar({ className }) {
|
|
|
2191
2767
|
strokeLinecap: "round",
|
|
2192
2768
|
strokeLinejoin: "round",
|
|
2193
2769
|
children: [
|
|
2194
|
-
/* @__PURE__ */
|
|
2195
|
-
/* @__PURE__ */
|
|
2196
|
-
/* @__PURE__ */
|
|
2770
|
+
/* @__PURE__ */ jsx7("path", { d: "M8 5V1M5 3l3 2 3-2" }),
|
|
2771
|
+
/* @__PURE__ */ jsx7("path", { d: "M8 11v4M5 13l3-2 3 2" }),
|
|
2772
|
+
/* @__PURE__ */ jsx7("path", { d: "M2 8h12" })
|
|
2197
2773
|
]
|
|
2198
2774
|
}
|
|
2199
2775
|
)
|
|
@@ -2208,31 +2784,7 @@ function SearchBar({ className }) {
|
|
|
2208
2784
|
}
|
|
2209
2785
|
|
|
2210
2786
|
// src/json-editor.tsx
|
|
2211
|
-
import { jsx as
|
|
2212
|
-
var DEFAULT_CSS_VARS = {
|
|
2213
|
-
"--vj-bg": "#1e1e1e",
|
|
2214
|
-
"--vj-bg-panel": "#252526",
|
|
2215
|
-
"--vj-bg-hover": "#2a2d2e",
|
|
2216
|
-
"--vj-bg-selected": "#2a5a1e",
|
|
2217
|
-
"--vj-bg-selected-muted": "#2a2d2e",
|
|
2218
|
-
"--vj-bg-match": "#3a3520",
|
|
2219
|
-
"--vj-bg-match-active": "#51502b",
|
|
2220
|
-
"--vj-border": "#333333",
|
|
2221
|
-
"--vj-border-subtle": "#2a2a2a",
|
|
2222
|
-
"--vj-text": "#cccccc",
|
|
2223
|
-
"--vj-text-muted": "#888888",
|
|
2224
|
-
"--vj-text-dim": "#666666",
|
|
2225
|
-
"--vj-text-dimmer": "#555555",
|
|
2226
|
-
"--vj-string": "#ce9178",
|
|
2227
|
-
"--vj-number": "#b5cea8",
|
|
2228
|
-
"--vj-boolean": "#569cd6",
|
|
2229
|
-
"--vj-accent": "#007acc",
|
|
2230
|
-
"--vj-accent-muted": "#094771",
|
|
2231
|
-
"--vj-input-bg": "#3c3c3c",
|
|
2232
|
-
"--vj-input-border": "#555555",
|
|
2233
|
-
"--vj-error": "#f48771",
|
|
2234
|
-
"--vj-font": "monospace"
|
|
2235
|
-
};
|
|
2787
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2236
2788
|
function JsonEditor({
|
|
2237
2789
|
value,
|
|
2238
2790
|
defaultValue,
|
|
@@ -2251,15 +2803,15 @@ function JsonEditor({
|
|
|
2251
2803
|
}) {
|
|
2252
2804
|
const isControlled = value !== void 0;
|
|
2253
2805
|
const initialValue = isControlled ? value : defaultValue ?? {};
|
|
2254
|
-
const [editorKey, setEditorKey] =
|
|
2255
|
-
const valueRef =
|
|
2256
|
-
|
|
2806
|
+
const [editorKey, setEditorKey] = useState8(0);
|
|
2807
|
+
const valueRef = useRef9(initialValue);
|
|
2808
|
+
useEffect8(() => {
|
|
2257
2809
|
if (isControlled && value !== valueRef.current) {
|
|
2258
2810
|
valueRef.current = value;
|
|
2259
2811
|
setEditorKey((k) => k + 1);
|
|
2260
2812
|
}
|
|
2261
2813
|
}, [value, isControlled]);
|
|
2262
|
-
const handleChange =
|
|
2814
|
+
const handleChange = useCallback8(
|
|
2263
2815
|
(newValue) => {
|
|
2264
2816
|
valueRef.current = newValue;
|
|
2265
2817
|
if (!readOnly) {
|
|
@@ -2277,25 +2829,35 @@ function JsonEditor({
|
|
|
2277
2829
|
...DEFAULT_CSS_VARS,
|
|
2278
2830
|
...style
|
|
2279
2831
|
};
|
|
2280
|
-
return /* @__PURE__ */
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
children: /* @__PURE__ */ jsx7(
|
|
2287
|
-
EditorLayout,
|
|
2288
|
-
{
|
|
2289
|
-
treeShowValues,
|
|
2290
|
-
treeShowCounts,
|
|
2291
|
-
editorShowDescriptions,
|
|
2292
|
-
editorShowCounts,
|
|
2293
|
-
sidebarOpen
|
|
2832
|
+
return /* @__PURE__ */ jsxs6("div", { className, "data-vj-root": "", style: containerStyle, children: [
|
|
2833
|
+
/* @__PURE__ */ jsx8(
|
|
2834
|
+
"style",
|
|
2835
|
+
{
|
|
2836
|
+
dangerouslySetInnerHTML: {
|
|
2837
|
+
__html: `@media(pointer:coarse){[data-vj-root]{--vj-input-font-size:16px}}`
|
|
2294
2838
|
}
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2839
|
+
}
|
|
2840
|
+
),
|
|
2841
|
+
/* @__PURE__ */ jsx8(
|
|
2842
|
+
VisualJson,
|
|
2843
|
+
{
|
|
2844
|
+
value: valueRef.current,
|
|
2845
|
+
onChange: readOnly ? void 0 : handleChange,
|
|
2846
|
+
schema,
|
|
2847
|
+
children: /* @__PURE__ */ jsx8(
|
|
2848
|
+
EditorLayout,
|
|
2849
|
+
{
|
|
2850
|
+
treeShowValues,
|
|
2851
|
+
treeShowCounts,
|
|
2852
|
+
editorShowDescriptions,
|
|
2853
|
+
editorShowCounts,
|
|
2854
|
+
sidebarOpen
|
|
2855
|
+
}
|
|
2856
|
+
)
|
|
2857
|
+
},
|
|
2858
|
+
editorKey
|
|
2859
|
+
)
|
|
2860
|
+
] });
|
|
2299
2861
|
}
|
|
2300
2862
|
function EditorLayout({
|
|
2301
2863
|
treeShowValues,
|
|
@@ -2304,14 +2866,14 @@ function EditorLayout({
|
|
|
2304
2866
|
editorShowCounts,
|
|
2305
2867
|
sidebarOpen
|
|
2306
2868
|
}) {
|
|
2307
|
-
const [sidebarWidth, setSidebarWidth] =
|
|
2308
|
-
const [isNarrow, setIsNarrow] =
|
|
2309
|
-
const [activePanel, setActivePanel] =
|
|
2310
|
-
const containerRef =
|
|
2311
|
-
const dragging =
|
|
2312
|
-
const startX =
|
|
2313
|
-
const startWidth =
|
|
2314
|
-
|
|
2869
|
+
const [sidebarWidth, setSidebarWidth] = useState8(280);
|
|
2870
|
+
const [isNarrow, setIsNarrow] = useState8(false);
|
|
2871
|
+
const [activePanel, setActivePanel] = useState8("tree");
|
|
2872
|
+
const containerRef = useRef9(null);
|
|
2873
|
+
const dragging = useRef9(false);
|
|
2874
|
+
const startX = useRef9(0);
|
|
2875
|
+
const startWidth = useRef9(0);
|
|
2876
|
+
useEffect8(() => {
|
|
2315
2877
|
function checkWidth() {
|
|
2316
2878
|
if (containerRef.current) {
|
|
2317
2879
|
setIsNarrow(containerRef.current.offsetWidth < 500);
|
|
@@ -2322,7 +2884,7 @@ function EditorLayout({
|
|
|
2322
2884
|
if (containerRef.current) observer.observe(containerRef.current);
|
|
2323
2885
|
return () => observer.disconnect();
|
|
2324
2886
|
}, []);
|
|
2325
|
-
const handleMouseDown =
|
|
2887
|
+
const handleMouseDown = useCallback8(
|
|
2326
2888
|
(e) => {
|
|
2327
2889
|
dragging.current = true;
|
|
2328
2890
|
startX.current = e.clientX;
|
|
@@ -2352,7 +2914,7 @@ function EditorLayout({
|
|
|
2352
2914
|
);
|
|
2353
2915
|
if (isNarrow) {
|
|
2354
2916
|
if (!sidebarOpen) {
|
|
2355
|
-
return /* @__PURE__ */
|
|
2917
|
+
return /* @__PURE__ */ jsx8(
|
|
2356
2918
|
"div",
|
|
2357
2919
|
{
|
|
2358
2920
|
ref: containerRef,
|
|
@@ -2362,7 +2924,7 @@ function EditorLayout({
|
|
|
2362
2924
|
flex: 1,
|
|
2363
2925
|
minHeight: 0
|
|
2364
2926
|
},
|
|
2365
|
-
children: /* @__PURE__ */
|
|
2927
|
+
children: /* @__PURE__ */ jsx8("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsx8(
|
|
2366
2928
|
FormView,
|
|
2367
2929
|
{
|
|
2368
2930
|
showDescriptions: editorShowDescriptions,
|
|
@@ -2372,7 +2934,7 @@ function EditorLayout({
|
|
|
2372
2934
|
}
|
|
2373
2935
|
);
|
|
2374
2936
|
}
|
|
2375
|
-
return /* @__PURE__ */
|
|
2937
|
+
return /* @__PURE__ */ jsxs6(
|
|
2376
2938
|
"div",
|
|
2377
2939
|
{
|
|
2378
2940
|
ref: containerRef,
|
|
@@ -2383,7 +2945,7 @@ function EditorLayout({
|
|
|
2383
2945
|
minHeight: 0
|
|
2384
2946
|
},
|
|
2385
2947
|
children: [
|
|
2386
|
-
/* @__PURE__ */
|
|
2948
|
+
/* @__PURE__ */ jsxs6(
|
|
2387
2949
|
"div",
|
|
2388
2950
|
{
|
|
2389
2951
|
style: {
|
|
@@ -2393,7 +2955,7 @@ function EditorLayout({
|
|
|
2393
2955
|
backgroundColor: "var(--vj-bg-panel, #252526)"
|
|
2394
2956
|
},
|
|
2395
2957
|
children: [
|
|
2396
|
-
/* @__PURE__ */
|
|
2958
|
+
/* @__PURE__ */ jsx8(
|
|
2397
2959
|
"button",
|
|
2398
2960
|
{
|
|
2399
2961
|
onClick: () => setActivePanel("tree"),
|
|
@@ -2410,7 +2972,7 @@ function EditorLayout({
|
|
|
2410
2972
|
children: "Tree"
|
|
2411
2973
|
}
|
|
2412
2974
|
),
|
|
2413
|
-
/* @__PURE__ */
|
|
2975
|
+
/* @__PURE__ */ jsx8(
|
|
2414
2976
|
"button",
|
|
2415
2977
|
{
|
|
2416
2978
|
onClick: () => setActivePanel("form"),
|
|
@@ -2430,7 +2992,7 @@ function EditorLayout({
|
|
|
2430
2992
|
]
|
|
2431
2993
|
}
|
|
2432
2994
|
),
|
|
2433
|
-
/* @__PURE__ */
|
|
2995
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: 1, minHeight: 0, overflow: "hidden" }, children: activePanel === "tree" ? /* @__PURE__ */ jsxs6(
|
|
2434
2996
|
"div",
|
|
2435
2997
|
{
|
|
2436
2998
|
style: {
|
|
@@ -2439,8 +3001,8 @@ function EditorLayout({
|
|
|
2439
3001
|
height: "100%"
|
|
2440
3002
|
},
|
|
2441
3003
|
children: [
|
|
2442
|
-
/* @__PURE__ */
|
|
2443
|
-
/* @__PURE__ */
|
|
3004
|
+
/* @__PURE__ */ jsx8(SearchBar, {}),
|
|
3005
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: 1, minHeight: 0, overflow: "auto" }, children: /* @__PURE__ */ jsx8(
|
|
2444
3006
|
TreeView,
|
|
2445
3007
|
{
|
|
2446
3008
|
showValues: treeShowValues,
|
|
@@ -2449,7 +3011,7 @@ function EditorLayout({
|
|
|
2449
3011
|
) })
|
|
2450
3012
|
]
|
|
2451
3013
|
}
|
|
2452
|
-
) : /* @__PURE__ */
|
|
3014
|
+
) : /* @__PURE__ */ jsx8(
|
|
2453
3015
|
"div",
|
|
2454
3016
|
{
|
|
2455
3017
|
style: {
|
|
@@ -2457,7 +3019,7 @@ function EditorLayout({
|
|
|
2457
3019
|
flexDirection: "column",
|
|
2458
3020
|
height: "100%"
|
|
2459
3021
|
},
|
|
2460
|
-
children: /* @__PURE__ */
|
|
3022
|
+
children: /* @__PURE__ */ jsx8("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsx8(
|
|
2461
3023
|
FormView,
|
|
2462
3024
|
{
|
|
2463
3025
|
showDescriptions: editorShowDescriptions,
|
|
@@ -2470,8 +3032,8 @@ function EditorLayout({
|
|
|
2470
3032
|
}
|
|
2471
3033
|
);
|
|
2472
3034
|
}
|
|
2473
|
-
return /* @__PURE__ */
|
|
2474
|
-
/* @__PURE__ */
|
|
3035
|
+
return /* @__PURE__ */ jsxs6("div", { ref: containerRef, style: { display: "flex", flex: 1, minHeight: 0 }, children: [
|
|
3036
|
+
/* @__PURE__ */ jsxs6(
|
|
2475
3037
|
"div",
|
|
2476
3038
|
{
|
|
2477
3039
|
style: {
|
|
@@ -2483,12 +3045,12 @@ function EditorLayout({
|
|
|
2483
3045
|
transition: "width 0.2s ease"
|
|
2484
3046
|
},
|
|
2485
3047
|
children: [
|
|
2486
|
-
/* @__PURE__ */
|
|
2487
|
-
/* @__PURE__ */
|
|
3048
|
+
/* @__PURE__ */ jsx8(SearchBar, {}),
|
|
3049
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: 1, minHeight: 0, overflow: "auto" }, children: /* @__PURE__ */ jsx8(TreeView, { showValues: treeShowValues, showCounts: treeShowCounts }) })
|
|
2488
3050
|
]
|
|
2489
3051
|
}
|
|
2490
3052
|
),
|
|
2491
|
-
sidebarOpen && /* @__PURE__ */
|
|
3053
|
+
sidebarOpen && /* @__PURE__ */ jsx8(
|
|
2492
3054
|
"div",
|
|
2493
3055
|
{
|
|
2494
3056
|
style: {
|
|
@@ -2498,7 +3060,7 @@ function EditorLayout({
|
|
|
2498
3060
|
position: "relative",
|
|
2499
3061
|
transition: "background-color 0.15s"
|
|
2500
3062
|
},
|
|
2501
|
-
children: /* @__PURE__ */
|
|
3063
|
+
children: /* @__PURE__ */ jsx8(
|
|
2502
3064
|
"div",
|
|
2503
3065
|
{
|
|
2504
3066
|
onMouseDown: handleMouseDown,
|
|
@@ -2527,7 +3089,7 @@ function EditorLayout({
|
|
|
2527
3089
|
)
|
|
2528
3090
|
}
|
|
2529
3091
|
),
|
|
2530
|
-
/* @__PURE__ */
|
|
3092
|
+
/* @__PURE__ */ jsx8(
|
|
2531
3093
|
"div",
|
|
2532
3094
|
{
|
|
2533
3095
|
style: {
|
|
@@ -2537,7 +3099,7 @@ function EditorLayout({
|
|
|
2537
3099
|
minWidth: 0,
|
|
2538
3100
|
overflow: "hidden"
|
|
2539
3101
|
},
|
|
2540
|
-
children: /* @__PURE__ */
|
|
3102
|
+
children: /* @__PURE__ */ jsx8("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsx8(
|
|
2541
3103
|
FormView,
|
|
2542
3104
|
{
|
|
2543
3105
|
showDescriptions: editorShowDescriptions,
|
|
@@ -2549,436 +3111,8 @@ function EditorLayout({
|
|
|
2549
3111
|
] });
|
|
2550
3112
|
}
|
|
2551
3113
|
|
|
2552
|
-
// src/property-editor.tsx
|
|
2553
|
-
import { useState as useState8, useCallback as useCallback8 } from "react";
|
|
2554
|
-
import {
|
|
2555
|
-
setValue as setValue2,
|
|
2556
|
-
setKey as setKey2,
|
|
2557
|
-
addProperty as addProperty2,
|
|
2558
|
-
removeNode as removeNode3,
|
|
2559
|
-
changeType as changeType2,
|
|
2560
|
-
duplicateNode as duplicateNode2,
|
|
2561
|
-
toJson as toJson3,
|
|
2562
|
-
getPropertySchema as getPropertySchema3,
|
|
2563
|
-
resolveRef as resolveRef2
|
|
2564
|
-
} from "@visual-json/core";
|
|
2565
|
-
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2566
|
-
var ALL_TYPES = [
|
|
2567
|
-
"string",
|
|
2568
|
-
"number",
|
|
2569
|
-
"boolean",
|
|
2570
|
-
"null",
|
|
2571
|
-
"object",
|
|
2572
|
-
"array"
|
|
2573
|
-
];
|
|
2574
|
-
function PropertyRow({ node, schemaProperty }) {
|
|
2575
|
-
const { state, actions } = useStudio();
|
|
2576
|
-
const isContainer = node.type === "object" || node.type === "array";
|
|
2577
|
-
const [hoveredRow, setHoveredRow] = useState8(false);
|
|
2578
|
-
function handleValueChange(newValue) {
|
|
2579
|
-
let parsed;
|
|
2580
|
-
if (newValue === "null") parsed = null;
|
|
2581
|
-
else if (newValue === "true") parsed = true;
|
|
2582
|
-
else if (newValue === "false") parsed = false;
|
|
2583
|
-
else if ((node.type === "number" || schemaProperty?.type === "number" || schemaProperty?.type === "integer") && !isNaN(Number(newValue)) && newValue.trim() !== "")
|
|
2584
|
-
parsed = Number(newValue);
|
|
2585
|
-
else parsed = newValue;
|
|
2586
|
-
const newTree = setValue2(state.tree, node.id, parsed);
|
|
2587
|
-
actions.setTree(newTree);
|
|
2588
|
-
}
|
|
2589
|
-
function handleKeyChange(newKey) {
|
|
2590
|
-
const newTree = setKey2(state.tree, node.id, newKey);
|
|
2591
|
-
actions.setTree(newTree);
|
|
2592
|
-
}
|
|
2593
|
-
function handleRemove() {
|
|
2594
|
-
const newTree = removeNode3(state.tree, node.id);
|
|
2595
|
-
actions.setTree(newTree);
|
|
2596
|
-
}
|
|
2597
|
-
function handleAddChild() {
|
|
2598
|
-
const key = node.type === "array" ? String(node.children.length) : `key${node.children.length}`;
|
|
2599
|
-
const newTree = addProperty2(state.tree, node.id, key, "");
|
|
2600
|
-
actions.setTree(newTree);
|
|
2601
|
-
}
|
|
2602
|
-
function displayValue() {
|
|
2603
|
-
if (isContainer) {
|
|
2604
|
-
return node.type === "array" ? `[${node.children.length} items]` : `{${node.children.length} keys}`;
|
|
2605
|
-
}
|
|
2606
|
-
if (node.value === null) return "";
|
|
2607
|
-
if (node.value === void 0) return "";
|
|
2608
|
-
if (typeof node.value === "string" && node.value === "") return "";
|
|
2609
|
-
return String(node.value);
|
|
2610
|
-
}
|
|
2611
|
-
const hasEnumValues = schemaProperty?.enum && schemaProperty.enum.length > 0;
|
|
2612
|
-
const description = schemaProperty?.description;
|
|
2613
|
-
return /* @__PURE__ */ jsxs6(
|
|
2614
|
-
"div",
|
|
2615
|
-
{
|
|
2616
|
-
onMouseEnter: () => setHoveredRow(true),
|
|
2617
|
-
onMouseLeave: () => setHoveredRow(false),
|
|
2618
|
-
children: [
|
|
2619
|
-
/* @__PURE__ */ jsxs6(
|
|
2620
|
-
"div",
|
|
2621
|
-
{
|
|
2622
|
-
style: {
|
|
2623
|
-
display: "flex",
|
|
2624
|
-
alignItems: "center",
|
|
2625
|
-
gap: 8,
|
|
2626
|
-
padding: "4px 12px",
|
|
2627
|
-
borderBottom: "1px solid var(--vj-border-subtle, #2a2a2a)",
|
|
2628
|
-
minHeight: 32,
|
|
2629
|
-
backgroundColor: hoveredRow ? "var(--vj-bg-hover, #2a2d2e)" : "transparent"
|
|
2630
|
-
},
|
|
2631
|
-
children: [
|
|
2632
|
-
/* @__PURE__ */ jsx8(
|
|
2633
|
-
"input",
|
|
2634
|
-
{
|
|
2635
|
-
value: node.key,
|
|
2636
|
-
onChange: (e) => handleKeyChange(e.target.value),
|
|
2637
|
-
style: {
|
|
2638
|
-
background: "none",
|
|
2639
|
-
border: "1px solid transparent",
|
|
2640
|
-
borderRadius: 3,
|
|
2641
|
-
color: "var(--vj-text, #cccccc)",
|
|
2642
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2643
|
-
fontSize: 13,
|
|
2644
|
-
padding: "2px 6px",
|
|
2645
|
-
width: 140,
|
|
2646
|
-
flexShrink: 0
|
|
2647
|
-
}
|
|
2648
|
-
}
|
|
2649
|
-
),
|
|
2650
|
-
!isContainer ? hasEnumValues ? /* @__PURE__ */ jsx8(
|
|
2651
|
-
"select",
|
|
2652
|
-
{
|
|
2653
|
-
value: displayValue(),
|
|
2654
|
-
onChange: (e) => handleValueChange(e.target.value),
|
|
2655
|
-
style: {
|
|
2656
|
-
background: "var(--vj-input-bg, #3c3c3c)",
|
|
2657
|
-
border: "1px solid var(--vj-input-border, #555555)",
|
|
2658
|
-
borderRadius: 3,
|
|
2659
|
-
color: node.type === "string" ? "var(--vj-string, #ce9178)" : "var(--vj-number, #b5cea8)",
|
|
2660
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2661
|
-
fontSize: 13,
|
|
2662
|
-
padding: "2px 6px",
|
|
2663
|
-
flex: 1,
|
|
2664
|
-
cursor: "pointer"
|
|
2665
|
-
},
|
|
2666
|
-
children: schemaProperty.enum.map((v, i) => /* @__PURE__ */ jsx8("option", { value: String(v), children: String(v) }, i))
|
|
2667
|
-
}
|
|
2668
|
-
) : /* @__PURE__ */ jsx8(
|
|
2669
|
-
"input",
|
|
2670
|
-
{
|
|
2671
|
-
value: displayValue(),
|
|
2672
|
-
onChange: (e) => handleValueChange(e.target.value),
|
|
2673
|
-
placeholder: "<value>",
|
|
2674
|
-
style: {
|
|
2675
|
-
background: "none",
|
|
2676
|
-
border: "1px solid transparent",
|
|
2677
|
-
borderRadius: 3,
|
|
2678
|
-
color: node.type === "string" ? "var(--vj-string, #ce9178)" : "var(--vj-number, #b5cea8)",
|
|
2679
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2680
|
-
fontSize: 13,
|
|
2681
|
-
padding: "2px 6px",
|
|
2682
|
-
flex: 1,
|
|
2683
|
-
textAlign: "right"
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
) : /* @__PURE__ */ jsx8(
|
|
2687
|
-
"span",
|
|
2688
|
-
{
|
|
2689
|
-
style: {
|
|
2690
|
-
color: "var(--vj-text-dim, #666666)",
|
|
2691
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2692
|
-
fontSize: 13,
|
|
2693
|
-
flex: 1,
|
|
2694
|
-
textAlign: "right"
|
|
2695
|
-
},
|
|
2696
|
-
children: displayValue()
|
|
2697
|
-
}
|
|
2698
|
-
),
|
|
2699
|
-
/* @__PURE__ */ jsxs6(
|
|
2700
|
-
"div",
|
|
2701
|
-
{
|
|
2702
|
-
style: {
|
|
2703
|
-
display: "flex",
|
|
2704
|
-
gap: 2,
|
|
2705
|
-
opacity: hoveredRow ? 1 : 0,
|
|
2706
|
-
transition: "opacity 0.1s",
|
|
2707
|
-
flexShrink: 0
|
|
2708
|
-
},
|
|
2709
|
-
children: [
|
|
2710
|
-
isContainer && /* @__PURE__ */ jsx8(
|
|
2711
|
-
"button",
|
|
2712
|
-
{
|
|
2713
|
-
onClick: handleAddChild,
|
|
2714
|
-
style: {
|
|
2715
|
-
background: "none",
|
|
2716
|
-
border: "none",
|
|
2717
|
-
color: "var(--vj-text-muted, #888888)",
|
|
2718
|
-
cursor: "pointer",
|
|
2719
|
-
padding: "2px 4px",
|
|
2720
|
-
fontSize: 15,
|
|
2721
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2722
|
-
borderRadius: 3,
|
|
2723
|
-
lineHeight: 1
|
|
2724
|
-
},
|
|
2725
|
-
title: "Add child",
|
|
2726
|
-
children: "+"
|
|
2727
|
-
}
|
|
2728
|
-
),
|
|
2729
|
-
/* @__PURE__ */ jsx8(
|
|
2730
|
-
"button",
|
|
2731
|
-
{
|
|
2732
|
-
onClick: handleRemove,
|
|
2733
|
-
style: {
|
|
2734
|
-
background: "none",
|
|
2735
|
-
border: "none",
|
|
2736
|
-
color: "var(--vj-text-muted, #888888)",
|
|
2737
|
-
cursor: "pointer",
|
|
2738
|
-
padding: "2px 4px",
|
|
2739
|
-
fontSize: 15,
|
|
2740
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2741
|
-
borderRadius: 3,
|
|
2742
|
-
lineHeight: 1
|
|
2743
|
-
},
|
|
2744
|
-
title: "Remove",
|
|
2745
|
-
children: "\xD7"
|
|
2746
|
-
}
|
|
2747
|
-
)
|
|
2748
|
-
]
|
|
2749
|
-
}
|
|
2750
|
-
)
|
|
2751
|
-
]
|
|
2752
|
-
}
|
|
2753
|
-
),
|
|
2754
|
-
description && /* @__PURE__ */ jsx8(
|
|
2755
|
-
"div",
|
|
2756
|
-
{
|
|
2757
|
-
style: {
|
|
2758
|
-
padding: "2px 12px 4px 44px",
|
|
2759
|
-
fontSize: 11,
|
|
2760
|
-
color: "var(--vj-text-dim, #666666)",
|
|
2761
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2762
|
-
borderBottom: "1px solid var(--vj-border-subtle, #2a2a2a)"
|
|
2763
|
-
},
|
|
2764
|
-
children: description
|
|
2765
|
-
}
|
|
2766
|
-
)
|
|
2767
|
-
]
|
|
2768
|
-
}
|
|
2769
|
-
);
|
|
2770
|
-
}
|
|
2771
|
-
function PropertyEditor({ className }) {
|
|
2772
|
-
const { state, actions } = useStudio();
|
|
2773
|
-
const selectedNode = state.selectedNodeId ? state.tree.nodesById.get(state.selectedNodeId) : null;
|
|
2774
|
-
const handleChangeType = useCallback8(
|
|
2775
|
-
(newType) => {
|
|
2776
|
-
if (!selectedNode) return;
|
|
2777
|
-
const newTree = changeType2(state.tree, selectedNode.id, newType);
|
|
2778
|
-
actions.setTree(newTree);
|
|
2779
|
-
},
|
|
2780
|
-
[state.tree, selectedNode, actions]
|
|
2781
|
-
);
|
|
2782
|
-
const handleDuplicate = useCallback8(() => {
|
|
2783
|
-
if (!selectedNode) return;
|
|
2784
|
-
const newTree = duplicateNode2(state.tree, selectedNode.id);
|
|
2785
|
-
actions.setTree(newTree);
|
|
2786
|
-
}, [state.tree, selectedNode, actions]);
|
|
2787
|
-
const handleCopyPath = useCallback8(() => {
|
|
2788
|
-
if (!selectedNode) return;
|
|
2789
|
-
navigator.clipboard.writeText(selectedNode.path).catch(() => {
|
|
2790
|
-
});
|
|
2791
|
-
}, [selectedNode]);
|
|
2792
|
-
const handleCopyValue = useCallback8(() => {
|
|
2793
|
-
if (!selectedNode) return;
|
|
2794
|
-
const value = toJson3(selectedNode);
|
|
2795
|
-
const text = typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
2796
|
-
navigator.clipboard.writeText(text).catch(() => {
|
|
2797
|
-
});
|
|
2798
|
-
}, [selectedNode]);
|
|
2799
|
-
if (!selectedNode) {
|
|
2800
|
-
return /* @__PURE__ */ jsx8(
|
|
2801
|
-
"div",
|
|
2802
|
-
{
|
|
2803
|
-
className,
|
|
2804
|
-
style: {
|
|
2805
|
-
display: "flex",
|
|
2806
|
-
alignItems: "center",
|
|
2807
|
-
justifyContent: "center",
|
|
2808
|
-
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
2809
|
-
color: "var(--vj-text-dimmer, #555555)",
|
|
2810
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2811
|
-
fontSize: 13,
|
|
2812
|
-
height: "100%"
|
|
2813
|
-
},
|
|
2814
|
-
children: "Select a node to edit"
|
|
2815
|
-
}
|
|
2816
|
-
);
|
|
2817
|
-
}
|
|
2818
|
-
const isContainer = selectedNode.type === "object" || selectedNode.type === "array";
|
|
2819
|
-
const schema = state.schema ?? void 0;
|
|
2820
|
-
const schemaTitle = schema?.title;
|
|
2821
|
-
function getChildSchema(childKey) {
|
|
2822
|
-
if (!schema || !selectedNode) return void 0;
|
|
2823
|
-
const childPath = selectedNode.path === "/" ? `/${childKey}` : `${selectedNode.path}/${childKey}`;
|
|
2824
|
-
const raw = getPropertySchema3(schema, childPath);
|
|
2825
|
-
return raw ? resolveRef2(raw, schema) : void 0;
|
|
2826
|
-
}
|
|
2827
|
-
function handleAdd() {
|
|
2828
|
-
if (!selectedNode) return;
|
|
2829
|
-
const key = selectedNode.type === "array" ? String(selectedNode.children.length) : `key${selectedNode.children.length}`;
|
|
2830
|
-
const newTree = addProperty2(state.tree, selectedNode.id, key, "");
|
|
2831
|
-
actions.setTree(newTree);
|
|
2832
|
-
}
|
|
2833
|
-
return /* @__PURE__ */ jsxs6(
|
|
2834
|
-
"div",
|
|
2835
|
-
{
|
|
2836
|
-
className,
|
|
2837
|
-
style: {
|
|
2838
|
-
backgroundColor: "var(--vj-bg, #1e1e1e)",
|
|
2839
|
-
color: "var(--vj-text, #cccccc)",
|
|
2840
|
-
overflow: "auto",
|
|
2841
|
-
height: "100%",
|
|
2842
|
-
display: "flex",
|
|
2843
|
-
flexDirection: "column"
|
|
2844
|
-
},
|
|
2845
|
-
children: [
|
|
2846
|
-
/* @__PURE__ */ jsxs6(
|
|
2847
|
-
"div",
|
|
2848
|
-
{
|
|
2849
|
-
style: {
|
|
2850
|
-
display: "flex",
|
|
2851
|
-
alignItems: "center",
|
|
2852
|
-
justifyContent: "space-between",
|
|
2853
|
-
padding: "6px 12px",
|
|
2854
|
-
borderBottom: "1px solid var(--vj-border, #333333)",
|
|
2855
|
-
fontSize: 12,
|
|
2856
|
-
color: "var(--vj-text-muted, #999999)",
|
|
2857
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2858
|
-
flexShrink: 0,
|
|
2859
|
-
backgroundColor: "var(--vj-bg-panel, #252526)"
|
|
2860
|
-
},
|
|
2861
|
-
children: [
|
|
2862
|
-
/* @__PURE__ */ jsxs6(
|
|
2863
|
-
"div",
|
|
2864
|
-
{
|
|
2865
|
-
style: {
|
|
2866
|
-
display: "flex",
|
|
2867
|
-
flexDirection: "column",
|
|
2868
|
-
gap: 2,
|
|
2869
|
-
flex: 1,
|
|
2870
|
-
minWidth: 0
|
|
2871
|
-
},
|
|
2872
|
-
children: [
|
|
2873
|
-
/* @__PURE__ */ jsx8(Breadcrumbs, {}),
|
|
2874
|
-
schemaTitle && /* @__PURE__ */ jsx8(
|
|
2875
|
-
"span",
|
|
2876
|
-
{
|
|
2877
|
-
style: { fontSize: 10, color: "var(--vj-text-dim, #666666)" },
|
|
2878
|
-
children: schemaTitle
|
|
2879
|
-
}
|
|
2880
|
-
)
|
|
2881
|
-
]
|
|
2882
|
-
}
|
|
2883
|
-
),
|
|
2884
|
-
/* @__PURE__ */ jsxs6(
|
|
2885
|
-
"div",
|
|
2886
|
-
{
|
|
2887
|
-
style: {
|
|
2888
|
-
display: "flex",
|
|
2889
|
-
alignItems: "center",
|
|
2890
|
-
gap: 4,
|
|
2891
|
-
flexShrink: 0
|
|
2892
|
-
},
|
|
2893
|
-
children: [
|
|
2894
|
-
/* @__PURE__ */ jsx8(
|
|
2895
|
-
"select",
|
|
2896
|
-
{
|
|
2897
|
-
value: selectedNode.type,
|
|
2898
|
-
onChange: (e) => handleChangeType(e.target.value),
|
|
2899
|
-
style: {
|
|
2900
|
-
background: "var(--vj-input-bg, #3c3c3c)",
|
|
2901
|
-
border: "1px solid var(--vj-input-border, #555555)",
|
|
2902
|
-
borderRadius: 3,
|
|
2903
|
-
color: "var(--vj-text, #cccccc)",
|
|
2904
|
-
fontSize: 11,
|
|
2905
|
-
fontFamily: "var(--vj-font, monospace)",
|
|
2906
|
-
padding: "1px 4px",
|
|
2907
|
-
cursor: "pointer"
|
|
2908
|
-
},
|
|
2909
|
-
title: "Change type",
|
|
2910
|
-
children: ALL_TYPES.map((t) => /* @__PURE__ */ jsx8("option", { value: t, children: t }, t))
|
|
2911
|
-
}
|
|
2912
|
-
),
|
|
2913
|
-
/* @__PURE__ */ jsx8(
|
|
2914
|
-
"button",
|
|
2915
|
-
{
|
|
2916
|
-
onClick: handleCopyPath,
|
|
2917
|
-
style: actionButtonStyle,
|
|
2918
|
-
title: "Copy path",
|
|
2919
|
-
children: "path"
|
|
2920
|
-
}
|
|
2921
|
-
),
|
|
2922
|
-
/* @__PURE__ */ jsx8(
|
|
2923
|
-
"button",
|
|
2924
|
-
{
|
|
2925
|
-
onClick: handleCopyValue,
|
|
2926
|
-
style: actionButtonStyle,
|
|
2927
|
-
title: "Copy value",
|
|
2928
|
-
children: "value"
|
|
2929
|
-
}
|
|
2930
|
-
),
|
|
2931
|
-
selectedNode.parentId && /* @__PURE__ */ jsx8(
|
|
2932
|
-
"button",
|
|
2933
|
-
{
|
|
2934
|
-
onClick: handleDuplicate,
|
|
2935
|
-
style: actionButtonStyle,
|
|
2936
|
-
title: "Duplicate",
|
|
2937
|
-
children: "dup"
|
|
2938
|
-
}
|
|
2939
|
-
),
|
|
2940
|
-
isContainer && /* @__PURE__ */ jsx8(
|
|
2941
|
-
"button",
|
|
2942
|
-
{
|
|
2943
|
-
onClick: handleAdd,
|
|
2944
|
-
style: {
|
|
2945
|
-
...actionButtonStyle,
|
|
2946
|
-
border: "1px solid var(--vj-input-border, #555555)"
|
|
2947
|
-
},
|
|
2948
|
-
children: "+ Add"
|
|
2949
|
-
}
|
|
2950
|
-
)
|
|
2951
|
-
]
|
|
2952
|
-
}
|
|
2953
|
-
)
|
|
2954
|
-
]
|
|
2955
|
-
}
|
|
2956
|
-
),
|
|
2957
|
-
/* @__PURE__ */ jsx8("div", { style: { flex: 1, overflow: "auto" }, children: isContainer ? selectedNode.children.map((child) => /* @__PURE__ */ jsx8(
|
|
2958
|
-
PropertyRow,
|
|
2959
|
-
{
|
|
2960
|
-
node: child,
|
|
2961
|
-
schemaProperty: getChildSchema(child.key)
|
|
2962
|
-
},
|
|
2963
|
-
child.id
|
|
2964
|
-
)) : /* @__PURE__ */ jsx8(PropertyRow, { node: selectedNode }) })
|
|
2965
|
-
]
|
|
2966
|
-
}
|
|
2967
|
-
);
|
|
2968
|
-
}
|
|
2969
|
-
var actionButtonStyle = {
|
|
2970
|
-
background: "none",
|
|
2971
|
-
border: "none",
|
|
2972
|
-
borderRadius: 3,
|
|
2973
|
-
color: "var(--vj-text-muted, #888888)",
|
|
2974
|
-
cursor: "pointer",
|
|
2975
|
-
padding: "1px 6px",
|
|
2976
|
-
fontSize: 11,
|
|
2977
|
-
fontFamily: "var(--vj-font, monospace)"
|
|
2978
|
-
};
|
|
2979
|
-
|
|
2980
3114
|
// src/diff-view.tsx
|
|
2981
|
-
import { useMemo as
|
|
3115
|
+
import { useMemo as useMemo7 } from "react";
|
|
2982
3116
|
import { computeDiff } from "@visual-json/core";
|
|
2983
3117
|
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2984
3118
|
var DIFF_COLORS = {
|
|
@@ -3057,7 +3191,7 @@ function DiffView({
|
|
|
3057
3191
|
currentJson,
|
|
3058
3192
|
className
|
|
3059
3193
|
}) {
|
|
3060
|
-
const entries =
|
|
3194
|
+
const entries = useMemo7(
|
|
3061
3195
|
() => computeDiff(originalJson, currentJson),
|
|
3062
3196
|
[originalJson, currentJson]
|
|
3063
3197
|
);
|
|
@@ -3136,7 +3270,6 @@ export {
|
|
|
3136
3270
|
DiffView,
|
|
3137
3271
|
FormView,
|
|
3138
3272
|
JsonEditor,
|
|
3139
|
-
PropertyEditor,
|
|
3140
3273
|
SearchBar,
|
|
3141
3274
|
StudioContext,
|
|
3142
3275
|
TreeView,
|