@visual-json/react 0.2.0 → 0.3.1
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/LICENSE +201 -0
- package/dist/index.js +204 -204
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +191 -188
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -39,20 +39,11 @@ var import_react10 = require("react");
|
|
|
39
39
|
|
|
40
40
|
// src/visual-json.tsx
|
|
41
41
|
var import_react2 = require("react");
|
|
42
|
-
var
|
|
43
|
-
|
|
44
|
-
// src/context.ts
|
|
45
|
-
var import_react = require("react");
|
|
46
|
-
var StudioContext = (0, import_react.createContext)(null);
|
|
47
|
-
function useStudio() {
|
|
48
|
-
const ctx = (0, import_react.useContext)(StudioContext);
|
|
49
|
-
if (!ctx) {
|
|
50
|
-
throw new Error("useStudio must be used within a <VisualJson> provider");
|
|
51
|
-
}
|
|
52
|
-
return ctx;
|
|
53
|
-
}
|
|
42
|
+
var import_core4 = require("@visual-json/core");
|
|
54
43
|
|
|
55
|
-
//
|
|
44
|
+
// ../../@internal/ui/dist/index.mjs
|
|
45
|
+
var import_core = require("@visual-json/core");
|
|
46
|
+
var import_core2 = require("@visual-json/core");
|
|
56
47
|
function getVisibleNodes(root, isExpanded) {
|
|
57
48
|
const result = [];
|
|
58
49
|
function walk(node) {
|
|
@@ -66,9 +57,171 @@ function getVisibleNodes(root, isExpanded) {
|
|
|
66
57
|
walk(root);
|
|
67
58
|
return result;
|
|
68
59
|
}
|
|
60
|
+
var LABEL_FIELDS = ["name", "type", "title", "id", "label", "key"];
|
|
61
|
+
function getDisplayKey(node, state) {
|
|
62
|
+
if (node.parentId === null) return "/";
|
|
63
|
+
const parent = state.nodesById.get(node.parentId);
|
|
64
|
+
if (parent?.type !== "array" || node.type !== "object") return node.key;
|
|
65
|
+
for (const field of LABEL_FIELDS) {
|
|
66
|
+
const child = node.children.find((c) => c.key === field);
|
|
67
|
+
if (child?.value != null && child.value !== "") {
|
|
68
|
+
return String(child.value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return node.key;
|
|
72
|
+
}
|
|
73
|
+
function collectAllIds(node) {
|
|
74
|
+
const ids = [node.id];
|
|
75
|
+
for (const child of node.children) {
|
|
76
|
+
ids.push(...collectAllIds(child));
|
|
77
|
+
}
|
|
78
|
+
return ids;
|
|
79
|
+
}
|
|
80
|
+
var DEFAULT_CSS_VARS = {
|
|
81
|
+
"--vj-bg": "#1e1e1e",
|
|
82
|
+
"--vj-bg-panel": "#252526",
|
|
83
|
+
"--vj-bg-hover": "#2a2d2e",
|
|
84
|
+
"--vj-bg-selected": "#2a5a1e",
|
|
85
|
+
"--vj-bg-selected-muted": "#2a2d2e",
|
|
86
|
+
"--vj-bg-match": "#3a3520",
|
|
87
|
+
"--vj-bg-match-active": "#51502b",
|
|
88
|
+
"--vj-border": "#333333",
|
|
89
|
+
"--vj-border-subtle": "#2a2a2a",
|
|
90
|
+
"--vj-text": "#cccccc",
|
|
91
|
+
"--vj-text-muted": "#888888",
|
|
92
|
+
"--vj-text-dim": "#666666",
|
|
93
|
+
"--vj-text-dimmer": "#555555",
|
|
94
|
+
"--vj-string": "#ce9178",
|
|
95
|
+
"--vj-number": "#b5cea8",
|
|
96
|
+
"--vj-boolean": "#569cd6",
|
|
97
|
+
"--vj-accent": "#007acc",
|
|
98
|
+
"--vj-accent-muted": "#094771",
|
|
99
|
+
"--vj-input-bg": "#3c3c3c",
|
|
100
|
+
"--vj-input-border": "#555555",
|
|
101
|
+
"--vj-error": "#f48771",
|
|
102
|
+
"--vj-font": "monospace",
|
|
103
|
+
"--vj-input-font-size": "13px"
|
|
104
|
+
};
|
|
105
|
+
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
106
|
+
function sortByTreeOrder(root, ids) {
|
|
107
|
+
const result = [];
|
|
108
|
+
function walk(node) {
|
|
109
|
+
if (ids.has(node.id)) result.push(node.id);
|
|
110
|
+
for (const child of node.children) walk(child);
|
|
111
|
+
}
|
|
112
|
+
walk(root);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
function computeDrop(tree, drag) {
|
|
116
|
+
const { draggedNodeIds, dropTargetNodeId, dropPosition } = drag;
|
|
117
|
+
if (draggedNodeIds.size === 0 || !dropTargetNodeId || !dropPosition)
|
|
118
|
+
return null;
|
|
119
|
+
const targetNode = tree.nodesById.get(dropTargetNodeId);
|
|
120
|
+
if (!targetNode || !targetNode.parentId) return null;
|
|
121
|
+
for (const id of draggedNodeIds) {
|
|
122
|
+
if ((0, import_core.isDescendant)(tree, dropTargetNodeId, id)) return null;
|
|
123
|
+
}
|
|
124
|
+
const targetParentId = targetNode.parentId;
|
|
125
|
+
const targetParent = tree.nodesById.get(targetParentId);
|
|
126
|
+
if (!targetParent) return null;
|
|
127
|
+
const parentChildren = targetParent.children;
|
|
128
|
+
const orderedDragIds = parentChildren.filter((c) => draggedNodeIds.has(c.id)).map((c) => c.id);
|
|
129
|
+
const allSameParent = orderedDragIds.length === draggedNodeIds.size && [...draggedNodeIds].every((id) => {
|
|
130
|
+
const n = tree.nodesById.get(id);
|
|
131
|
+
return n?.parentId === targetParentId;
|
|
132
|
+
});
|
|
133
|
+
if (allSameParent) {
|
|
134
|
+
return (0, import_core.reorderChildrenMulti)(
|
|
135
|
+
tree,
|
|
136
|
+
targetParentId,
|
|
137
|
+
orderedDragIds,
|
|
138
|
+
dropTargetNodeId,
|
|
139
|
+
dropPosition
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const orderedIds = sortByTreeOrder(tree.root, draggedNodeIds);
|
|
143
|
+
const draggedNodes = orderedIds.map((id) => tree.nodesById.get(id)).filter((n) => !!n && n.parentId !== null).map((n) => structuredClone(n));
|
|
144
|
+
let newTree = tree;
|
|
145
|
+
for (const id of [...orderedIds].reverse()) {
|
|
146
|
+
if (newTree.nodesById.has(id)) {
|
|
147
|
+
newTree = (0, import_core.removeNode)(newTree, id);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const updatedTarget = newTree.nodesById.get(dropTargetNodeId);
|
|
151
|
+
if (!updatedTarget || !updatedTarget.parentId) return null;
|
|
152
|
+
const updatedParent = newTree.nodesById.get(updatedTarget.parentId);
|
|
153
|
+
if (!updatedParent) return null;
|
|
154
|
+
let insertIdx = updatedParent.children.findIndex(
|
|
155
|
+
(c) => c.id === dropTargetNodeId
|
|
156
|
+
);
|
|
157
|
+
if (dropPosition === "after") insertIdx++;
|
|
158
|
+
for (let i = 0; i < draggedNodes.length; i++) {
|
|
159
|
+
newTree = (0, import_core.insertNode)(
|
|
160
|
+
newTree,
|
|
161
|
+
updatedParent.id,
|
|
162
|
+
draggedNodes[i],
|
|
163
|
+
insertIdx + i
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
return newTree;
|
|
167
|
+
}
|
|
168
|
+
function setMultiDragImage(dataTransfer, count, rootEl) {
|
|
169
|
+
const ghost = document.createElement("div");
|
|
170
|
+
ghost.textContent = `${count} selected`;
|
|
171
|
+
const root = rootEl ?? document.querySelector("[data-form-container], [role='tree']");
|
|
172
|
+
const cs = root ? getComputedStyle(root) : null;
|
|
173
|
+
const bg = cs?.getPropertyValue("--vj-bg-selected").trim() || DEFAULT_CSS_VARS["--vj-bg-selected"];
|
|
174
|
+
const fg = cs?.getPropertyValue("--vj-text-selected").trim() || cs?.getPropertyValue("--vj-text").trim() || DEFAULT_CSS_VARS["--vj-text"];
|
|
175
|
+
const font = cs?.getPropertyValue("--vj-font").trim() || DEFAULT_CSS_VARS["--vj-font"];
|
|
176
|
+
ghost.style.cssText = [
|
|
177
|
+
"position:fixed",
|
|
178
|
+
"top:-1000px",
|
|
179
|
+
"left:-1000px",
|
|
180
|
+
"padding:4px 12px",
|
|
181
|
+
`background:${bg}`,
|
|
182
|
+
`color:${fg}`,
|
|
183
|
+
`font-family:${font}`,
|
|
184
|
+
"font-size:13px",
|
|
185
|
+
"border-radius:4px",
|
|
186
|
+
"white-space:nowrap",
|
|
187
|
+
"pointer-events:none"
|
|
188
|
+
].join(";");
|
|
189
|
+
document.body.appendChild(ghost);
|
|
190
|
+
dataTransfer.setDragImage(ghost, 0, 14);
|
|
191
|
+
requestAnimationFrame(() => ghost.remove());
|
|
192
|
+
}
|
|
193
|
+
var DIFF_COLORS = {
|
|
194
|
+
added: { bg: "#1e3a1e", marker: "+", label: "#4ec94e" },
|
|
195
|
+
removed: { bg: "#3a1e1e", marker: "-", label: "#f48771" },
|
|
196
|
+
changed: { bg: "#3a3a1e", marker: "~", label: "#dcdcaa" }
|
|
197
|
+
};
|
|
198
|
+
function formatValue(value) {
|
|
199
|
+
if (value === void 0) return "";
|
|
200
|
+
if (value === null) return "null";
|
|
201
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
202
|
+
if (typeof value === "object") {
|
|
203
|
+
const json = JSON.stringify(value, null, 2);
|
|
204
|
+
if (json.length > 80) {
|
|
205
|
+
return JSON.stringify(value).slice(0, 77) + "...";
|
|
206
|
+
}
|
|
207
|
+
return json;
|
|
208
|
+
}
|
|
209
|
+
return String(value);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/context.ts
|
|
213
|
+
var import_react = require("react");
|
|
214
|
+
var StudioContext = (0, import_react.createContext)(null);
|
|
215
|
+
function useStudio() {
|
|
216
|
+
const ctx = (0, import_react.useContext)(StudioContext);
|
|
217
|
+
if (!ctx) {
|
|
218
|
+
throw new Error("useStudio must be used within a <VisualJson> provider");
|
|
219
|
+
}
|
|
220
|
+
return ctx;
|
|
221
|
+
}
|
|
69
222
|
|
|
70
223
|
// src/selection-utils.ts
|
|
71
|
-
var
|
|
224
|
+
var import_core3 = require("@visual-json/core");
|
|
72
225
|
function computeSelectAllIds(tree, focusedNodeId, currentlySelected) {
|
|
73
226
|
if (!focusedNodeId) return null;
|
|
74
227
|
let node = tree.nodesById.get(focusedNodeId);
|
|
@@ -114,7 +267,7 @@ function deleteSelectedNodes(tree, selectedIds, visibleNodes) {
|
|
|
114
267
|
let newTree = tree;
|
|
115
268
|
for (const id of idsToDelete) {
|
|
116
269
|
if (newTree.nodesById.has(id)) {
|
|
117
|
-
newTree = (0,
|
|
270
|
+
newTree = (0, import_core3.removeNode)(newTree, id);
|
|
118
271
|
}
|
|
119
272
|
}
|
|
120
273
|
let nextFocusId = null;
|
|
@@ -139,20 +292,13 @@ function deleteSelectedNodes(tree, selectedIds, visibleNodes) {
|
|
|
139
292
|
|
|
140
293
|
// src/visual-json.tsx
|
|
141
294
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
142
|
-
function collectAllIds(node) {
|
|
143
|
-
const ids = [node.id];
|
|
144
|
-
for (const child of node.children) {
|
|
145
|
-
ids.push(...collectAllIds(child));
|
|
146
|
-
}
|
|
147
|
-
return ids;
|
|
148
|
-
}
|
|
149
295
|
function VisualJson({
|
|
150
296
|
value,
|
|
151
297
|
onChange,
|
|
152
298
|
schema,
|
|
153
299
|
children
|
|
154
300
|
}) {
|
|
155
|
-
const [tree, setTreeState] = (0, import_react2.useState)(() => (0,
|
|
301
|
+
const [tree, setTreeState] = (0, import_react2.useState)(() => (0, import_core4.fromJson)(value));
|
|
156
302
|
const [focusedNodeId, setFocusedNodeId] = (0, import_react2.useState)(null);
|
|
157
303
|
const [selectedNodeIds, setSelectedNodeIdsState] = (0, import_react2.useState)(
|
|
158
304
|
() => /* @__PURE__ */ new Set()
|
|
@@ -189,7 +335,7 @@ function VisualJson({
|
|
|
189
335
|
const setVisibleNodesOverride = (0, import_react2.useCallback)((nodes) => {
|
|
190
336
|
visibleNodesOverrideRef.current = nodes;
|
|
191
337
|
}, []);
|
|
192
|
-
const historyRef = (0, import_react2.useRef)(new
|
|
338
|
+
const historyRef = (0, import_react2.useRef)(new import_core4.History());
|
|
193
339
|
const isInternalChange = (0, import_react2.useRef)(false);
|
|
194
340
|
const hasMounted = (0, import_react2.useRef)(false);
|
|
195
341
|
const [canUndo, setCanUndo] = (0, import_react2.useState)(false);
|
|
@@ -214,11 +360,11 @@ function VisualJson({
|
|
|
214
360
|
isInternalChange.current = false;
|
|
215
361
|
return;
|
|
216
362
|
}
|
|
217
|
-
const newTree = (0,
|
|
363
|
+
const newTree = (0, import_core4.fromJson)(value);
|
|
218
364
|
setTreeState(newTree);
|
|
219
365
|
setExpandedNodeIds(/* @__PURE__ */ new Set([newTree.root.id]));
|
|
220
366
|
focusSelectAndDrillDown(null);
|
|
221
|
-
historyRef.current = new
|
|
367
|
+
historyRef.current = new import_core4.History();
|
|
222
368
|
historyRef.current.push(newTree);
|
|
223
369
|
setCanUndo(false);
|
|
224
370
|
setCanRedo(false);
|
|
@@ -234,7 +380,7 @@ function VisualJson({
|
|
|
234
380
|
setCanUndo(historyRef.current.canUndo);
|
|
235
381
|
setCanRedo(historyRef.current.canRedo);
|
|
236
382
|
isInternalChange.current = true;
|
|
237
|
-
onChange?.((0,
|
|
383
|
+
onChange?.((0, import_core4.toJson)(newTree.root));
|
|
238
384
|
},
|
|
239
385
|
[onChange]
|
|
240
386
|
);
|
|
@@ -245,7 +391,7 @@ function VisualJson({
|
|
|
245
391
|
setCanUndo(historyRef.current.canUndo);
|
|
246
392
|
setCanRedo(historyRef.current.canRedo);
|
|
247
393
|
isInternalChange.current = true;
|
|
248
|
-
onChange?.((0,
|
|
394
|
+
onChange?.((0, import_core4.toJson)(prev.root));
|
|
249
395
|
}
|
|
250
396
|
}, [onChange]);
|
|
251
397
|
const redo = (0, import_react2.useCallback)(() => {
|
|
@@ -255,7 +401,7 @@ function VisualJson({
|
|
|
255
401
|
setCanUndo(historyRef.current.canUndo);
|
|
256
402
|
setCanRedo(historyRef.current.canRedo);
|
|
257
403
|
isInternalChange.current = true;
|
|
258
|
-
onChange?.((0,
|
|
404
|
+
onChange?.((0, import_core4.toJson)(next.root));
|
|
259
405
|
}
|
|
260
406
|
}, [onChange]);
|
|
261
407
|
(0, import_react2.useEffect)(() => {
|
|
@@ -374,14 +520,14 @@ function VisualJson({
|
|
|
374
520
|
setSearchMatchNodeIds(/* @__PURE__ */ new Set());
|
|
375
521
|
return;
|
|
376
522
|
}
|
|
377
|
-
const matches = (0,
|
|
523
|
+
const matches = (0, import_core4.searchNodes)(tree, query);
|
|
378
524
|
setSearchMatches(matches);
|
|
379
525
|
setSearchMatchIndex(0);
|
|
380
526
|
const matchIds = new Set(matches.map((m) => m.nodeId));
|
|
381
527
|
setSearchMatchNodeIds(matchIds);
|
|
382
528
|
if (matches.length > 0) {
|
|
383
529
|
const firstId = matches[0].nodeId;
|
|
384
|
-
const ancestors = (0,
|
|
530
|
+
const ancestors = (0, import_core4.getAncestorIds)(
|
|
385
531
|
tree,
|
|
386
532
|
matches.map((m) => m.nodeId)
|
|
387
533
|
);
|
|
@@ -409,7 +555,7 @@ function VisualJson({
|
|
|
409
555
|
}, [searchMatches, searchMatchIndex, focusSelectAndDrillDown]);
|
|
410
556
|
(0, import_react2.useEffect)(() => {
|
|
411
557
|
if (!searchQuery.trim()) return;
|
|
412
|
-
const matches = (0,
|
|
558
|
+
const matches = (0, import_core4.searchNodes)(tree, searchQuery);
|
|
413
559
|
setSearchMatches(matches);
|
|
414
560
|
setSearchMatchIndex(
|
|
415
561
|
(prev) => Math.min(prev, Math.max(matches.length - 1, 0))
|
|
@@ -496,7 +642,7 @@ function VisualJson({
|
|
|
496
642
|
|
|
497
643
|
// src/tree-view.tsx
|
|
498
644
|
var import_react5 = require("react");
|
|
499
|
-
var
|
|
645
|
+
var import_core6 = require("@visual-json/core");
|
|
500
646
|
|
|
501
647
|
// src/context-menu.tsx
|
|
502
648
|
var import_react3 = require("react");
|
|
@@ -595,92 +741,17 @@ function ContextMenu({ x, y, items, onClose }) {
|
|
|
595
741
|
);
|
|
596
742
|
}
|
|
597
743
|
|
|
598
|
-
// src/display-key.ts
|
|
599
|
-
var LABEL_FIELDS = ["name", "type", "title", "id", "label", "key"];
|
|
600
|
-
function getDisplayKey(node, state) {
|
|
601
|
-
if (node.parentId === null) return "/";
|
|
602
|
-
const parent = state.nodesById.get(node.parentId);
|
|
603
|
-
if (parent?.type !== "array" || node.type !== "object") return node.key;
|
|
604
|
-
for (const field of LABEL_FIELDS) {
|
|
605
|
-
const child = node.children.find((c) => c.key === field);
|
|
606
|
-
if (child?.value != null && child.value !== "") {
|
|
607
|
-
return String(child.value);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
return node.key;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
744
|
// src/use-drag-drop.ts
|
|
614
745
|
var import_react4 = require("react");
|
|
615
|
-
var
|
|
616
|
-
|
|
617
|
-
// src/theme.ts
|
|
618
|
-
var DEFAULT_CSS_VARS = {
|
|
619
|
-
"--vj-bg": "#1e1e1e",
|
|
620
|
-
"--vj-bg-panel": "#252526",
|
|
621
|
-
"--vj-bg-hover": "#2a2d2e",
|
|
622
|
-
"--vj-bg-selected": "#2a5a1e",
|
|
623
|
-
"--vj-bg-selected-muted": "#2a2d2e",
|
|
624
|
-
"--vj-bg-match": "#3a3520",
|
|
625
|
-
"--vj-bg-match-active": "#51502b",
|
|
626
|
-
"--vj-border": "#333333",
|
|
627
|
-
"--vj-border-subtle": "#2a2a2a",
|
|
628
|
-
"--vj-text": "#cccccc",
|
|
629
|
-
"--vj-text-muted": "#888888",
|
|
630
|
-
"--vj-text-dim": "#666666",
|
|
631
|
-
"--vj-text-dimmer": "#555555",
|
|
632
|
-
"--vj-string": "#ce9178",
|
|
633
|
-
"--vj-number": "#b5cea8",
|
|
634
|
-
"--vj-boolean": "#569cd6",
|
|
635
|
-
"--vj-accent": "#007acc",
|
|
636
|
-
"--vj-accent-muted": "#094771",
|
|
637
|
-
"--vj-input-bg": "#3c3c3c",
|
|
638
|
-
"--vj-input-border": "#555555",
|
|
639
|
-
"--vj-error": "#f48771",
|
|
640
|
-
"--vj-font": "monospace",
|
|
641
|
-
"--vj-input-font-size": "13px"
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
// src/use-drag-drop.ts
|
|
645
|
-
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
746
|
+
var import_core5 = require("@visual-json/core");
|
|
747
|
+
var EMPTY_SET2 = Object.freeze(/* @__PURE__ */ new Set());
|
|
646
748
|
var INITIAL_DRAG_STATE = {
|
|
647
|
-
draggedNodeIds:
|
|
749
|
+
draggedNodeIds: EMPTY_SET2,
|
|
648
750
|
dropTargetNodeId: null,
|
|
649
751
|
dropPosition: null
|
|
650
752
|
};
|
|
651
|
-
function
|
|
652
|
-
|
|
653
|
-
function walk(node) {
|
|
654
|
-
if (ids.has(node.id)) result.push(node.id);
|
|
655
|
-
for (const child of node.children) walk(child);
|
|
656
|
-
}
|
|
657
|
-
walk(root);
|
|
658
|
-
return result;
|
|
659
|
-
}
|
|
660
|
-
function setMultiDragImage(e, count) {
|
|
661
|
-
const ghost = document.createElement("div");
|
|
662
|
-
ghost.textContent = `${count} selected`;
|
|
663
|
-
const root = document.querySelector("[data-form-container], [role='tree']");
|
|
664
|
-
const cs = root ? getComputedStyle(root) : null;
|
|
665
|
-
const bg = cs?.getPropertyValue("--vj-bg-selected").trim() || DEFAULT_CSS_VARS["--vj-bg-selected"];
|
|
666
|
-
const fg = cs?.getPropertyValue("--vj-text-selected").trim() || cs?.getPropertyValue("--vj-text").trim() || DEFAULT_CSS_VARS["--vj-text"];
|
|
667
|
-
const font = cs?.getPropertyValue("--vj-font").trim() || DEFAULT_CSS_VARS["--vj-font"];
|
|
668
|
-
ghost.style.cssText = [
|
|
669
|
-
"position:fixed",
|
|
670
|
-
"top:-1000px",
|
|
671
|
-
"left:-1000px",
|
|
672
|
-
"padding:4px 12px",
|
|
673
|
-
`background:${bg}`,
|
|
674
|
-
`color:${fg}`,
|
|
675
|
-
`font-family:${font}`,
|
|
676
|
-
"font-size:13px",
|
|
677
|
-
"border-radius:4px",
|
|
678
|
-
"white-space:nowrap",
|
|
679
|
-
"pointer-events:none"
|
|
680
|
-
].join(";");
|
|
681
|
-
document.body.appendChild(ghost);
|
|
682
|
-
e.dataTransfer.setDragImage(ghost, 0, 14);
|
|
683
|
-
requestAnimationFrame(() => ghost.remove());
|
|
753
|
+
function setMultiDragImage2(e, count) {
|
|
754
|
+
setMultiDragImage(e.dataTransfer, count);
|
|
684
755
|
}
|
|
685
756
|
function useDragDrop(visibleNodes, selectedNodeIds) {
|
|
686
757
|
const { state, actions } = useStudio();
|
|
@@ -712,7 +783,7 @@ function useDragDrop(visibleNodes, selectedNodeIds) {
|
|
|
712
783
|
(nodeId, position) => {
|
|
713
784
|
const draggedIds = dragStateRef.current.draggedNodeIds;
|
|
714
785
|
for (const draggedId of draggedIds) {
|
|
715
|
-
if (nodeId === draggedId || (0,
|
|
786
|
+
if (nodeId === draggedId || (0, import_core5.isDescendant)(state.tree, nodeId, draggedId)) {
|
|
716
787
|
return;
|
|
717
788
|
}
|
|
718
789
|
}
|
|
@@ -741,62 +812,9 @@ function useDragDrop(visibleNodes, selectedNodeIds) {
|
|
|
741
812
|
setDragState(INITIAL_DRAG_STATE);
|
|
742
813
|
}, []);
|
|
743
814
|
const handleDrop = (0, import_react4.useCallback)(() => {
|
|
744
|
-
const
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
if (!targetNode || !targetNode.parentId) return;
|
|
748
|
-
for (const id of draggedNodeIds) {
|
|
749
|
-
if ((0, import_core3.isDescendant)(state.tree, dropTargetNodeId, id)) return;
|
|
750
|
-
}
|
|
751
|
-
const targetParentId = targetNode.parentId;
|
|
752
|
-
const targetParent = state.tree.nodesById.get(targetParentId);
|
|
753
|
-
if (!targetParent) return;
|
|
754
|
-
const parentChildren = targetParent.children;
|
|
755
|
-
const orderedDragIds = parentChildren.filter((c) => draggedNodeIds.has(c.id)).map((c) => c.id);
|
|
756
|
-
const allSameParent = orderedDragIds.length === draggedNodeIds.size && [...draggedNodeIds].every((id) => {
|
|
757
|
-
const n = state.tree.nodesById.get(id);
|
|
758
|
-
return n?.parentId === targetParentId;
|
|
759
|
-
});
|
|
760
|
-
if (allSameParent) {
|
|
761
|
-
const newTree = (0, import_core3.reorderChildrenMulti)(
|
|
762
|
-
state.tree,
|
|
763
|
-
targetParentId,
|
|
764
|
-
orderedDragIds,
|
|
765
|
-
dropTargetNodeId,
|
|
766
|
-
dropPosition
|
|
767
|
-
);
|
|
768
|
-
actions.setTree(newTree);
|
|
769
|
-
} else {
|
|
770
|
-
const orderedIds = sortByTreeOrder(state.tree.root, draggedNodeIds);
|
|
771
|
-
const draggedNodes = orderedIds.map((id) => state.tree.nodesById.get(id)).filter((n) => !!n && n.parentId !== null).map((n) => structuredClone(n));
|
|
772
|
-
let newTree = state.tree;
|
|
773
|
-
for (const id of [...orderedIds].reverse()) {
|
|
774
|
-
if (newTree.nodesById.has(id)) {
|
|
775
|
-
newTree = (0, import_core3.removeNode)(newTree, id);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
const updatedTarget = newTree.nodesById.get(dropTargetNodeId);
|
|
779
|
-
if (!updatedTarget || !updatedTarget.parentId) {
|
|
780
|
-
setDragState(INITIAL_DRAG_STATE);
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
const updatedParent = newTree.nodesById.get(updatedTarget.parentId);
|
|
784
|
-
if (!updatedParent) {
|
|
785
|
-
setDragState(INITIAL_DRAG_STATE);
|
|
786
|
-
return;
|
|
787
|
-
}
|
|
788
|
-
let insertIdx = updatedParent.children.findIndex(
|
|
789
|
-
(c) => c.id === dropTargetNodeId
|
|
790
|
-
);
|
|
791
|
-
if (dropPosition === "after") insertIdx++;
|
|
792
|
-
for (let i = 0; i < draggedNodes.length; i++) {
|
|
793
|
-
newTree = (0, import_core3.insertNode)(
|
|
794
|
-
newTree,
|
|
795
|
-
updatedParent.id,
|
|
796
|
-
draggedNodes[i],
|
|
797
|
-
insertIdx + i
|
|
798
|
-
);
|
|
799
|
-
}
|
|
815
|
+
const currentDragState = dragStateRef.current;
|
|
816
|
+
const newTree = computeDrop(state.tree, currentDragState);
|
|
817
|
+
if (newTree) {
|
|
800
818
|
actions.setTree(newTree);
|
|
801
819
|
}
|
|
802
820
|
setDragState(INITIAL_DRAG_STATE);
|
|
@@ -881,7 +899,7 @@ function TreeNodeRow({
|
|
|
881
899
|
onDragStart: (e) => {
|
|
882
900
|
e.dataTransfer.effectAllowed = "move";
|
|
883
901
|
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
884
|
-
|
|
902
|
+
setMultiDragImage2(e, state.selectedNodeIds.size);
|
|
885
903
|
}
|
|
886
904
|
onDragStart(node.id);
|
|
887
905
|
},
|
|
@@ -1077,7 +1095,7 @@ function TreeView({
|
|
|
1077
1095
|
items.push({
|
|
1078
1096
|
label: "Copy value as JSON",
|
|
1079
1097
|
action: () => {
|
|
1080
|
-
const val = (0,
|
|
1098
|
+
const val = (0, import_core6.toJson)(node);
|
|
1081
1099
|
const text = typeof val === "string" ? val : JSON.stringify(val, null, 2);
|
|
1082
1100
|
navigator.clipboard.writeText(text).catch(() => {
|
|
1083
1101
|
});
|
|
@@ -1088,7 +1106,7 @@ function TreeView({
|
|
|
1088
1106
|
items.push({
|
|
1089
1107
|
label: "Duplicate",
|
|
1090
1108
|
action: () => {
|
|
1091
|
-
const newTree = (0,
|
|
1109
|
+
const newTree = (0, import_core6.duplicateNode)(state.tree, node.id);
|
|
1092
1110
|
actions.setTree(newTree);
|
|
1093
1111
|
}
|
|
1094
1112
|
});
|
|
@@ -1102,7 +1120,7 @@ function TreeView({
|
|
|
1102
1120
|
].filter((t) => t !== node.type).map((t) => ({
|
|
1103
1121
|
label: `Change to ${t}`,
|
|
1104
1122
|
action: () => {
|
|
1105
|
-
const newTree = (0,
|
|
1123
|
+
const newTree = (0, import_core6.changeType)(state.tree, node.id, t);
|
|
1106
1124
|
actions.setTree(newTree);
|
|
1107
1125
|
}
|
|
1108
1126
|
}));
|
|
@@ -1112,7 +1130,7 @@ function TreeView({
|
|
|
1112
1130
|
items.push({
|
|
1113
1131
|
label: "Delete",
|
|
1114
1132
|
action: () => {
|
|
1115
|
-
const newTree = (0,
|
|
1133
|
+
const newTree = (0, import_core6.removeNode)(state.tree, node.id);
|
|
1116
1134
|
actions.setTree(newTree);
|
|
1117
1135
|
}
|
|
1118
1136
|
});
|
|
@@ -1295,7 +1313,7 @@ function TreeView({
|
|
|
1295
1313
|
|
|
1296
1314
|
// src/form-view.tsx
|
|
1297
1315
|
var import_react8 = require("react");
|
|
1298
|
-
var
|
|
1316
|
+
var import_core7 = require("@visual-json/core");
|
|
1299
1317
|
|
|
1300
1318
|
// src/breadcrumbs.tsx
|
|
1301
1319
|
var import_react6 = require("react");
|
|
@@ -1650,9 +1668,9 @@ function EnumInput({
|
|
|
1650
1668
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1651
1669
|
function getResolvedSchema(schema, rootSchema, path) {
|
|
1652
1670
|
if (!schema) return void 0;
|
|
1653
|
-
const raw = (0,
|
|
1671
|
+
const raw = (0, import_core7.getPropertySchema)(schema, path, rootSchema);
|
|
1654
1672
|
if (!raw) return void 0;
|
|
1655
|
-
return (0,
|
|
1673
|
+
return (0, import_core7.resolveRef)(raw, rootSchema ?? schema);
|
|
1656
1674
|
}
|
|
1657
1675
|
function getValueColor(node) {
|
|
1658
1676
|
if (node.type === "boolean" || node.type === "null")
|
|
@@ -1739,25 +1757,25 @@ function FormField({
|
|
|
1739
1757
|
} else {
|
|
1740
1758
|
parsed = newValue;
|
|
1741
1759
|
}
|
|
1742
|
-
const newTree = (0,
|
|
1760
|
+
const newTree = (0, import_core7.setValue)(state.tree, node.id, parsed);
|
|
1743
1761
|
actions.setTree(newTree);
|
|
1744
1762
|
},
|
|
1745
1763
|
[state.tree, node.id, node.type, actions, propSchema]
|
|
1746
1764
|
);
|
|
1747
1765
|
const handleKeyChange = (0, import_react8.useCallback)(
|
|
1748
1766
|
(newKey) => {
|
|
1749
|
-
const newTree = (0,
|
|
1767
|
+
const newTree = (0, import_core7.setKey)(state.tree, node.id, newKey);
|
|
1750
1768
|
actions.setTree(newTree);
|
|
1751
1769
|
},
|
|
1752
1770
|
[state.tree, node.id, actions]
|
|
1753
1771
|
);
|
|
1754
1772
|
const handleRemove = (0, import_react8.useCallback)(() => {
|
|
1755
|
-
const newTree = (0,
|
|
1773
|
+
const newTree = (0, import_core7.removeNode)(state.tree, node.id);
|
|
1756
1774
|
actions.setTree(newTree);
|
|
1757
1775
|
}, [state.tree, node.id, actions]);
|
|
1758
1776
|
const handleAddChild = (0, import_react8.useCallback)(() => {
|
|
1759
1777
|
const key = node.type === "array" ? String(node.children.length) : `newKey${node.children.length}`;
|
|
1760
|
-
const newTree = (0,
|
|
1778
|
+
const newTree = (0, import_core7.addProperty)(state.tree, node.id, key, "");
|
|
1761
1779
|
actions.setTree(newTree);
|
|
1762
1780
|
}, [state.tree, node.id, node.type, node.children.length, actions]);
|
|
1763
1781
|
const description = propSchema?.description;
|
|
@@ -1776,7 +1794,7 @@ function FormField({
|
|
|
1776
1794
|
onDragStart: (e) => {
|
|
1777
1795
|
e.dataTransfer.effectAllowed = "move";
|
|
1778
1796
|
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
1779
|
-
|
|
1797
|
+
setMultiDragImage2(e, state.selectedNodeIds.size);
|
|
1780
1798
|
}
|
|
1781
1799
|
onDragStart(node.id);
|
|
1782
1800
|
},
|
|
@@ -1989,7 +2007,7 @@ function FormField({
|
|
|
1989
2007
|
onDragStart: (e) => {
|
|
1990
2008
|
e.dataTransfer.effectAllowed = "move";
|
|
1991
2009
|
if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
|
|
1992
|
-
|
|
2010
|
+
setMultiDragImage2(e, state.selectedNodeIds.size);
|
|
1993
2011
|
}
|
|
1994
2012
|
onDragStart(node.id);
|
|
1995
2013
|
},
|
|
@@ -3109,26 +3127,8 @@ function EditorLayout({
|
|
|
3109
3127
|
|
|
3110
3128
|
// src/diff-view.tsx
|
|
3111
3129
|
var import_react11 = require("react");
|
|
3112
|
-
var
|
|
3130
|
+
var import_core8 = require("@visual-json/core");
|
|
3113
3131
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
3114
|
-
var DIFF_COLORS = {
|
|
3115
|
-
added: { bg: "#1e3a1e", marker: "+", label: "#4ec94e" },
|
|
3116
|
-
removed: { bg: "#3a1e1e", marker: "-", label: "#f48771" },
|
|
3117
|
-
changed: { bg: "#3a3a1e", marker: "~", label: "#dcdcaa" }
|
|
3118
|
-
};
|
|
3119
|
-
function formatValue(value) {
|
|
3120
|
-
if (value === void 0) return "";
|
|
3121
|
-
if (value === null) return "null";
|
|
3122
|
-
if (typeof value === "string") return JSON.stringify(value);
|
|
3123
|
-
if (typeof value === "object") {
|
|
3124
|
-
const json = JSON.stringify(value, null, 2);
|
|
3125
|
-
if (json.length > 80) {
|
|
3126
|
-
return JSON.stringify(value).slice(0, 77) + "...";
|
|
3127
|
-
}
|
|
3128
|
-
return json;
|
|
3129
|
-
}
|
|
3130
|
-
return String(value);
|
|
3131
|
-
}
|
|
3132
3132
|
function DiffRow({ entry }) {
|
|
3133
3133
|
const colors = DIFF_COLORS[entry.type];
|
|
3134
3134
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
@@ -3188,7 +3188,7 @@ function DiffView({
|
|
|
3188
3188
|
className
|
|
3189
3189
|
}) {
|
|
3190
3190
|
const entries = (0, import_react11.useMemo)(
|
|
3191
|
-
() => (0,
|
|
3191
|
+
() => (0, import_core8.computeDiff)(originalJson, currentJson),
|
|
3192
3192
|
[originalJson, currentJson]
|
|
3193
3193
|
);
|
|
3194
3194
|
const added = entries.filter((e) => e.type === "added").length;
|