Skip to content

Commit c194ac2

Browse files
authored
Fix (better drag-n-drop): Scope Handler & Scope right-click Menu for adding new nodes (#232)
* add drag handler & scope context menu * clean up
1 parent ec458cf commit c194ac2

File tree

3 files changed

+45
-10
lines changed

3 files changed

+45
-10
lines changed

ui/src/components/Canvas.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,10 +524,22 @@ function CanvasImpl() {
524524
const [showContextMenu, setShowContextMenu] = useState(false);
525525
const [points, setPoints] = useState({ x: 0, y: 0 });
526526
const [client, setClient] = useState({ x: 0, y: 0 });
527+
const [parentNode, setParentNode] = useState("ROOT");
527528

528529
const onPaneContextMenu = (event) => {
529530
event.preventDefault();
530531
setShowContextMenu(true);
532+
setParentNode("ROOT");
533+
setPoints({ x: event.pageX, y: event.pageY });
534+
setClient({ x: event.clientX, y: event.clientY });
535+
};
536+
537+
const onNodeContextMenu = (event, node) => {
538+
if (node?.type !== "scope") return;
539+
540+
event.preventDefault();
541+
setShowContextMenu(true);
542+
setParentNode(node.id);
531543
setPoints({ x: event.pageX, y: event.pageY });
532544
setClient({ x: event.clientX, y: event.clientY });
533545
};
@@ -603,6 +615,7 @@ function CanvasImpl() {
603615
maxZoom={10}
604616
minZoom={0.1}
605617
onPaneContextMenu={onPaneContextMenu}
618+
onNodeContextMenu={onNodeContextMenu}
606619
nodeTypes={nodeTypes}
607620
// custom edge for easy connect
608621
edgeTypes={edgeTypes}
@@ -657,17 +670,22 @@ function CanvasImpl() {
657670
x={points.x}
658671
y={points.y}
659672
addCode={() =>
660-
addNode("code", project({ x: client.x, y: client.y }))
673+
addNode("code", project({ x: client.x, y: client.y }), parentNode)
661674
}
662675
addScope={() =>
663-
addNode("scope", project({ x: client.x, y: client.y }))
676+
addNode(
677+
"scope",
678+
project({ x: client.x, y: client.y }),
679+
parentNode
680+
)
664681
}
665682
addRich={() =>
666-
addNode("rich", project({ x: client.x, y: client.y }))
683+
addNode("rich", project({ x: client.x, y: client.y }), parentNode)
667684
}
668685
onShareClick={() => {
669686
setShareOpen(true);
670687
}}
688+
parentNode={null}
671689
/>
672690
)}
673691
{shareOpen && <ShareProjDialog open={shareOpen} id={repoId || ""} />}

ui/src/components/nodes/Scope.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export const ScopeNode = memo<NodeProps>(function ScopeNode({
113113
border: isCutting ? "dashed 2px red" : "solid 1px #d6dee6",
114114
borderRadius: "4px",
115115
}}
116-
className="custom-drag-handle"
117116
>
118117
{/* <NodeResizer color="#ff0071" minWidth={100} minHeight={30} /> */}
119118
<NodeResizeControl
@@ -194,6 +193,7 @@ export const ScopeNode = memo<NodeProps>(function ScopeNode({
194193
<Box
195194
// bgcolor={"rgb(225,225,225)"}
196195
sx={{ display: "flex" }}
196+
className="custom-drag-handle"
197197
>
198198
{devMode && (
199199
<Box

ui/src/lib/store/canvasSlice.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ function getScopeAt(
169169
function getNodePositionInsideScope(
170170
node: Node,
171171
scope: Node,
172-
nodesMap
172+
nodesMap,
173+
nodeHeight: number = 0
173174
): XYPosition {
174175
// compute the actual position
175176
let [x, y] = getAbsPos(node, nodesMap);
@@ -178,11 +179,11 @@ function getNodePositionInsideScope(
178179
y -= dy;
179180
// auto-align the node to, keep it bound in the scope
180181
// FIXME: it assumes the scope must be larger than the node
181-
182182
x = Math.max(x, 0);
183183
x = Math.min(x, scope.width! - node.width!);
184184
y = Math.max(y, 0);
185-
y = Math.min(y, scope.height! - node.height!);
185+
// FIXME: node.height can be undefined
186+
y = Math.min(y, scope.height! - nodeHeight);
186187
return { x, y };
187188
}
188189

@@ -250,7 +251,11 @@ export interface CanvasSlice {
250251
setPaneFocus: () => void;
251252
setPaneBlur: () => void;
252253

253-
addNode: (type: "code" | "scope" | "rich", position: XYPosition) => void;
254+
addNode: (
255+
type: "code" | "scope" | "rich",
256+
position: XYPosition,
257+
parent: string
258+
) => void;
254259

255260
pastingNodes?: Node[];
256261
headPastingNodes?: Set<string>;
@@ -390,7 +395,7 @@ export const createCanvasSlice: StateCreator<MyState, [], [], CanvasSlice> = (
390395
get().addPod({
391396
id: node.id,
392397
children: [],
393-
parent,
398+
parent: "ROOT",
394399
type: nodetype2dbtype(node.type || ""),
395400
lang: "python",
396401
x: node.position.x,
@@ -401,6 +406,10 @@ export const createCanvasSlice: StateCreator<MyState, [], [], CanvasSlice> = (
401406
dirty: true,
402407
pending: true,
403408
});
409+
if (parent !== "ROOT") {
410+
// we don't assign its parent when created, because we have to adjust its position to make it inside its parent.
411+
get().moveIntoScope(node.id, parent);
412+
}
404413
get().updateView();
405414
},
406415

@@ -610,7 +619,15 @@ export const createCanvasSlice: StateCreator<MyState, [], [], CanvasSlice> = (
610619
}
611620
// let [x, y] = getAbsPos(node, nodesMap);
612621
// let position = getNodePositionInsideParent(node, scope, { x, y });
613-
let position = getNodePositionInsideScope(node, scope, nodesMap);
622+
623+
// FIXME: since richNode and codeNode doesn't have height when it's created, we have to pass its height manually in case crash.
624+
const nodeHeight = get().getPod(nodeId)?.height || 0;
625+
let position = getNodePositionInsideScope(
626+
node,
627+
scope,
628+
nodesMap,
629+
nodeHeight
630+
);
614631
let newNode: Node = {
615632
...node,
616633
position,

0 commit comments

Comments
 (0)