@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/dist/index.mjs CHANGED
@@ -22,18 +22,17 @@ import {
22
22
  getAncestorIds
23
23
  } from "@visual-json/core";
24
24
 
25
- // src/context.ts
26
- import { createContext, useContext } from "react";
27
- var StudioContext = createContext(null);
28
- function useStudio() {
29
- const ctx = useContext(StudioContext);
30
- if (!ctx) {
31
- throw new Error("useStudio must be used within a <VisualJson> provider");
32
- }
33
- return ctx;
34
- }
35
-
36
- // src/get-visible-nodes.ts
25
+ // ../../@internal/ui/dist/index.mjs
26
+ import {
27
+ reorderChildrenMulti,
28
+ removeNode,
29
+ insertNode,
30
+ isDescendant
31
+ } from "@visual-json/core";
32
+ import {
33
+ getPropertySchema,
34
+ resolveRef
35
+ } from "@visual-json/core";
37
36
  function getVisibleNodes(root, isExpanded) {
38
37
  const result = [];
39
38
  function walk(node) {
@@ -47,9 +46,171 @@ function getVisibleNodes(root, isExpanded) {
47
46
  walk(root);
48
47
  return result;
49
48
  }
49
+ var LABEL_FIELDS = ["name", "type", "title", "id", "label", "key"];
50
+ function getDisplayKey(node, state) {
51
+ if (node.parentId === null) return "/";
52
+ const parent = state.nodesById.get(node.parentId);
53
+ if (parent?.type !== "array" || node.type !== "object") return node.key;
54
+ for (const field of LABEL_FIELDS) {
55
+ const child = node.children.find((c) => c.key === field);
56
+ if (child?.value != null && child.value !== "") {
57
+ return String(child.value);
58
+ }
59
+ }
60
+ return node.key;
61
+ }
62
+ function collectAllIds(node) {
63
+ const ids = [node.id];
64
+ for (const child of node.children) {
65
+ ids.push(...collectAllIds(child));
66
+ }
67
+ return ids;
68
+ }
69
+ var DEFAULT_CSS_VARS = {
70
+ "--vj-bg": "#1e1e1e",
71
+ "--vj-bg-panel": "#252526",
72
+ "--vj-bg-hover": "#2a2d2e",
73
+ "--vj-bg-selected": "#2a5a1e",
74
+ "--vj-bg-selected-muted": "#2a2d2e",
75
+ "--vj-bg-match": "#3a3520",
76
+ "--vj-bg-match-active": "#51502b",
77
+ "--vj-border": "#333333",
78
+ "--vj-border-subtle": "#2a2a2a",
79
+ "--vj-text": "#cccccc",
80
+ "--vj-text-muted": "#888888",
81
+ "--vj-text-dim": "#666666",
82
+ "--vj-text-dimmer": "#555555",
83
+ "--vj-string": "#ce9178",
84
+ "--vj-number": "#b5cea8",
85
+ "--vj-boolean": "#569cd6",
86
+ "--vj-accent": "#007acc",
87
+ "--vj-accent-muted": "#094771",
88
+ "--vj-input-bg": "#3c3c3c",
89
+ "--vj-input-border": "#555555",
90
+ "--vj-error": "#f48771",
91
+ "--vj-font": "monospace",
92
+ "--vj-input-font-size": "13px"
93
+ };
94
+ var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
95
+ function sortByTreeOrder(root, ids) {
96
+ const result = [];
97
+ function walk(node) {
98
+ if (ids.has(node.id)) result.push(node.id);
99
+ for (const child of node.children) walk(child);
100
+ }
101
+ walk(root);
102
+ return result;
103
+ }
104
+ function computeDrop(tree, drag) {
105
+ const { draggedNodeIds, dropTargetNodeId, dropPosition } = drag;
106
+ if (draggedNodeIds.size === 0 || !dropTargetNodeId || !dropPosition)
107
+ return null;
108
+ const targetNode = tree.nodesById.get(dropTargetNodeId);
109
+ if (!targetNode || !targetNode.parentId) return null;
110
+ for (const id of draggedNodeIds) {
111
+ if (isDescendant(tree, dropTargetNodeId, id)) return null;
112
+ }
113
+ const targetParentId = targetNode.parentId;
114
+ const targetParent = tree.nodesById.get(targetParentId);
115
+ if (!targetParent) return null;
116
+ const parentChildren = targetParent.children;
117
+ const orderedDragIds = parentChildren.filter((c) => draggedNodeIds.has(c.id)).map((c) => c.id);
118
+ const allSameParent = orderedDragIds.length === draggedNodeIds.size && [...draggedNodeIds].every((id) => {
119
+ const n = tree.nodesById.get(id);
120
+ return n?.parentId === targetParentId;
121
+ });
122
+ if (allSameParent) {
123
+ return reorderChildrenMulti(
124
+ tree,
125
+ targetParentId,
126
+ orderedDragIds,
127
+ dropTargetNodeId,
128
+ dropPosition
129
+ );
130
+ }
131
+ const orderedIds = sortByTreeOrder(tree.root, draggedNodeIds);
132
+ const draggedNodes = orderedIds.map((id) => tree.nodesById.get(id)).filter((n) => !!n && n.parentId !== null).map((n) => structuredClone(n));
133
+ let newTree = tree;
134
+ for (const id of [...orderedIds].reverse()) {
135
+ if (newTree.nodesById.has(id)) {
136
+ newTree = removeNode(newTree, id);
137
+ }
138
+ }
139
+ const updatedTarget = newTree.nodesById.get(dropTargetNodeId);
140
+ if (!updatedTarget || !updatedTarget.parentId) return null;
141
+ const updatedParent = newTree.nodesById.get(updatedTarget.parentId);
142
+ if (!updatedParent) return null;
143
+ let insertIdx = updatedParent.children.findIndex(
144
+ (c) => c.id === dropTargetNodeId
145
+ );
146
+ if (dropPosition === "after") insertIdx++;
147
+ for (let i = 0; i < draggedNodes.length; i++) {
148
+ newTree = insertNode(
149
+ newTree,
150
+ updatedParent.id,
151
+ draggedNodes[i],
152
+ insertIdx + i
153
+ );
154
+ }
155
+ return newTree;
156
+ }
157
+ function setMultiDragImage(dataTransfer, count, rootEl) {
158
+ const ghost = document.createElement("div");
159
+ ghost.textContent = `${count} selected`;
160
+ const root = rootEl ?? document.querySelector("[data-form-container], [role='tree']");
161
+ const cs = root ? getComputedStyle(root) : null;
162
+ const bg = cs?.getPropertyValue("--vj-bg-selected").trim() || DEFAULT_CSS_VARS["--vj-bg-selected"];
163
+ const fg = cs?.getPropertyValue("--vj-text-selected").trim() || cs?.getPropertyValue("--vj-text").trim() || DEFAULT_CSS_VARS["--vj-text"];
164
+ const font = cs?.getPropertyValue("--vj-font").trim() || DEFAULT_CSS_VARS["--vj-font"];
165
+ ghost.style.cssText = [
166
+ "position:fixed",
167
+ "top:-1000px",
168
+ "left:-1000px",
169
+ "padding:4px 12px",
170
+ `background:${bg}`,
171
+ `color:${fg}`,
172
+ `font-family:${font}`,
173
+ "font-size:13px",
174
+ "border-radius:4px",
175
+ "white-space:nowrap",
176
+ "pointer-events:none"
177
+ ].join(";");
178
+ document.body.appendChild(ghost);
179
+ dataTransfer.setDragImage(ghost, 0, 14);
180
+ requestAnimationFrame(() => ghost.remove());
181
+ }
182
+ var DIFF_COLORS = {
183
+ added: { bg: "#1e3a1e", marker: "+", label: "#4ec94e" },
184
+ removed: { bg: "#3a1e1e", marker: "-", label: "#f48771" },
185
+ changed: { bg: "#3a3a1e", marker: "~", label: "#dcdcaa" }
186
+ };
187
+ function formatValue(value) {
188
+ if (value === void 0) return "";
189
+ if (value === null) return "null";
190
+ if (typeof value === "string") return JSON.stringify(value);
191
+ if (typeof value === "object") {
192
+ const json = JSON.stringify(value, null, 2);
193
+ if (json.length > 80) {
194
+ return JSON.stringify(value).slice(0, 77) + "...";
195
+ }
196
+ return json;
197
+ }
198
+ return String(value);
199
+ }
200
+
201
+ // src/context.ts
202
+ import { createContext, useContext } from "react";
203
+ var StudioContext = createContext(null);
204
+ function useStudio() {
205
+ const ctx = useContext(StudioContext);
206
+ if (!ctx) {
207
+ throw new Error("useStudio must be used within a <VisualJson> provider");
208
+ }
209
+ return ctx;
210
+ }
50
211
 
51
212
  // src/selection-utils.ts
52
- import { removeNode } from "@visual-json/core";
213
+ import { removeNode as removeNode2 } from "@visual-json/core";
53
214
  function computeSelectAllIds(tree, focusedNodeId, currentlySelected) {
54
215
  if (!focusedNodeId) return null;
55
216
  let node = tree.nodesById.get(focusedNodeId);
@@ -95,7 +256,7 @@ function deleteSelectedNodes(tree, selectedIds, visibleNodes) {
95
256
  let newTree = tree;
96
257
  for (const id of idsToDelete) {
97
258
  if (newTree.nodesById.has(id)) {
98
- newTree = removeNode(newTree, id);
259
+ newTree = removeNode2(newTree, id);
99
260
  }
100
261
  }
101
262
  let nextFocusId = null;
@@ -120,13 +281,6 @@ function deleteSelectedNodes(tree, selectedIds, visibleNodes) {
120
281
 
121
282
  // src/visual-json.tsx
122
283
  import { jsx } from "react/jsx-runtime";
123
- function collectAllIds(node) {
124
- const ids = [node.id];
125
- for (const child of node.children) {
126
- ids.push(...collectAllIds(child));
127
- }
128
- return ids;
129
- }
130
284
  function VisualJson({
131
285
  value,
132
286
  onChange,
@@ -581,97 +735,17 @@ function ContextMenu({ x, y, items, onClose }) {
581
735
  );
582
736
  }
583
737
 
584
- // src/display-key.ts
585
- var LABEL_FIELDS = ["name", "type", "title", "id", "label", "key"];
586
- function getDisplayKey(node, state) {
587
- if (node.parentId === null) return "/";
588
- const parent = state.nodesById.get(node.parentId);
589
- if (parent?.type !== "array" || node.type !== "object") return node.key;
590
- for (const field of LABEL_FIELDS) {
591
- const child = node.children.find((c) => c.key === field);
592
- if (child?.value != null && child.value !== "") {
593
- return String(child.value);
594
- }
595
- }
596
- return node.key;
597
- }
598
-
599
738
  // src/use-drag-drop.ts
600
739
  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
- };
634
-
635
- // src/use-drag-drop.ts
636
- var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
740
+ import { isDescendant as isDescendant2 } from "@visual-json/core";
741
+ var EMPTY_SET2 = Object.freeze(/* @__PURE__ */ new Set());
637
742
  var INITIAL_DRAG_STATE = {
638
- draggedNodeIds: EMPTY_SET,
743
+ draggedNodeIds: EMPTY_SET2,
639
744
  dropTargetNodeId: null,
640
745
  dropPosition: null
641
746
  };
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());
747
+ function setMultiDragImage2(e, count) {
748
+ setMultiDragImage(e.dataTransfer, count);
675
749
  }
676
750
  function useDragDrop(visibleNodes, selectedNodeIds) {
677
751
  const { state, actions } = useStudio();
@@ -703,7 +777,7 @@ function useDragDrop(visibleNodes, selectedNodeIds) {
703
777
  (nodeId, position) => {
704
778
  const draggedIds = dragStateRef.current.draggedNodeIds;
705
779
  for (const draggedId of draggedIds) {
706
- if (nodeId === draggedId || isDescendant(state.tree, nodeId, draggedId)) {
780
+ if (nodeId === draggedId || isDescendant2(state.tree, nodeId, draggedId)) {
707
781
  return;
708
782
  }
709
783
  }
@@ -732,62 +806,9 @@ function useDragDrop(visibleNodes, selectedNodeIds) {
732
806
  setDragState(INITIAL_DRAG_STATE);
733
807
  }, []);
734
808
  const handleDrop = useCallback2(() => {
735
- const { draggedNodeIds, dropTargetNodeId, dropPosition } = dragStateRef.current;
736
- if (draggedNodeIds.size === 0 || !dropTargetNodeId || !dropPosition) return;
737
- const targetNode = state.tree.nodesById.get(dropTargetNodeId);
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);
767
- }
768
- }
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
789
- );
790
- }
809
+ const currentDragState = dragStateRef.current;
810
+ const newTree = computeDrop(state.tree, currentDragState);
811
+ if (newTree) {
791
812
  actions.setTree(newTree);
792
813
  }
793
814
  setDragState(INITIAL_DRAG_STATE);
@@ -872,7 +893,7 @@ function TreeNodeRow({
872
893
  onDragStart: (e) => {
873
894
  e.dataTransfer.effectAllowed = "move";
874
895
  if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
875
- setMultiDragImage(e, state.selectedNodeIds.size);
896
+ setMultiDragImage2(e, state.selectedNodeIds.size);
876
897
  }
877
898
  onDragStart(node.id);
878
899
  },
@@ -1291,8 +1312,8 @@ import {
1291
1312
  setKey,
1292
1313
  addProperty,
1293
1314
  removeNode as removeNode4,
1294
- getPropertySchema,
1295
- resolveRef
1315
+ getPropertySchema as getPropertySchema2,
1316
+ resolveRef as resolveRef2
1296
1317
  } from "@visual-json/core";
1297
1318
 
1298
1319
  // src/breadcrumbs.tsx
@@ -1654,9 +1675,9 @@ function EnumInput({
1654
1675
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1655
1676
  function getResolvedSchema(schema, rootSchema, path) {
1656
1677
  if (!schema) return void 0;
1657
- const raw = getPropertySchema(schema, path, rootSchema);
1678
+ const raw = getPropertySchema2(schema, path, rootSchema);
1658
1679
  if (!raw) return void 0;
1659
- return resolveRef(raw, rootSchema ?? schema);
1680
+ return resolveRef2(raw, rootSchema ?? schema);
1660
1681
  }
1661
1682
  function getValueColor(node) {
1662
1683
  if (node.type === "boolean" || node.type === "null")
@@ -1780,7 +1801,7 @@ function FormField({
1780
1801
  onDragStart: (e) => {
1781
1802
  e.dataTransfer.effectAllowed = "move";
1782
1803
  if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
1783
- setMultiDragImage(e, state.selectedNodeIds.size);
1804
+ setMultiDragImage2(e, state.selectedNodeIds.size);
1784
1805
  }
1785
1806
  onDragStart(node.id);
1786
1807
  },
@@ -1993,7 +2014,7 @@ function FormField({
1993
2014
  onDragStart: (e) => {
1994
2015
  e.dataTransfer.effectAllowed = "move";
1995
2016
  if (state.selectedNodeIds.size > 1 && state.selectedNodeIds.has(node.id)) {
1996
- setMultiDragImage(e, state.selectedNodeIds.size);
2017
+ setMultiDragImage2(e, state.selectedNodeIds.size);
1997
2018
  }
1998
2019
  onDragStart(node.id);
1999
2020
  },
@@ -3115,24 +3136,6 @@ function EditorLayout({
3115
3136
  import { useMemo as useMemo7 } from "react";
3116
3137
  import { computeDiff } from "@visual-json/core";
3117
3138
  import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
3118
- var DIFF_COLORS = {
3119
- added: { bg: "#1e3a1e", marker: "+", label: "#4ec94e" },
3120
- removed: { bg: "#3a1e1e", marker: "-", label: "#f48771" },
3121
- changed: { bg: "#3a3a1e", marker: "~", label: "#dcdcaa" }
3122
- };
3123
- function formatValue(value) {
3124
- if (value === void 0) return "";
3125
- if (value === null) return "null";
3126
- if (typeof value === "string") return JSON.stringify(value);
3127
- if (typeof value === "object") {
3128
- const json = JSON.stringify(value, null, 2);
3129
- if (json.length > 80) {
3130
- return JSON.stringify(value).slice(0, 77) + "...";
3131
- }
3132
- return json;
3133
- }
3134
- return String(value);
3135
- }
3136
3139
  function DiffRow({ entry }) {
3137
3140
  const colors = DIFF_COLORS[entry.type];
3138
3141
  return /* @__PURE__ */ jsxs7(