Skip to content

Commit d39f808

Browse files
committed
added code
1 parent 6b3fa9c commit d39f808

File tree

4 files changed

+97
-43
lines changed

4 files changed

+97
-43
lines changed

app/layout.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import React from "react";
44
import { Providers } from "@/app/providers";
55

66
export const metadata: Metadata = {
7-
title: "Create Next App",
8-
description: "Generated by create next app",
7+
title: "Reactflow Prototype",
8+
description: "Code by Ranit Manik",
99
};
1010

1111
export default function RootLayout({

app/page.jsx

+33-38
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import "@xyflow/react/dist/style.css";
2222
import { v4 as uuidv4 } from "uuid";
2323

2424
import CustomEdge from "./_components/custom-edge";
25-
import { LabeledGroupNode } from "../components/labeled-group-node";
26-
import { CustomChildNode } from "../components/custom-child-node";
2725
import { toast, Toaster } from "sonner";
2826
import "./index.css";
2927
import { useDnD } from "./context/drag-and-drop";
3028
import { Sidebar } from "./_components/sidebar";
29+
import { LabeledGroupNode } from "../components/labeled-group-node";
30+
import { CustomChildNode } from "../components/custom-child-node";
3131

3232
const nodeTypes = {
3333
LabeledGroupNode,
@@ -43,7 +43,23 @@ export default function Page() {
4343
const [nodes, setNodes] = useNodesState([]);
4444
const [edges, setEdges] = useEdgesState([]);
4545

46-
// drag and drop providers setup
46+
// Persistent indices using useRef
47+
const stageIndex = useRef(1);
48+
const processIndex = useRef(1);
49+
50+
const getStageIndex = useCallback(() => {
51+
const currentIndex = stageIndex.current;
52+
stageIndex.current += 1;
53+
return currentIndex;
54+
}, []);
55+
56+
const getProcessIndex = useCallback(() => {
57+
const currentIndex = processIndex.current;
58+
processIndex.current += 1;
59+
return currentIndex;
60+
}, []);
61+
62+
// Drag-and-drop providers setup
4763
const { screenToFlowPosition } = useReactFlow();
4864
const [type] = useDnD();
4965

@@ -60,8 +76,6 @@ export default function Page() {
6076
data: { label: "Dependent" },
6177
};
6278

63-
// const panOnDrag = [1, 2];
64-
6579
const onConnect = useCallback(
6680
(params) => {
6781
// Prevent self-connections
@@ -84,8 +98,6 @@ export default function Page() {
8498
[setEdges],
8599
);
86100

87-
// drag and drop functions
88-
89101
const onDragOver = useCallback((event) => {
90102
event.preventDefault();
91103
event.dataTransfer.dropEffect = "move";
@@ -109,8 +121,12 @@ export default function Page() {
109121
id: uuidv4(),
110122
type,
111123
position,
112-
data: { label: `${type} node` },
113-
/*measured: { width: 160, height: 20 }, // Default size for new node*/
124+
data: {
125+
label:
126+
type === "LabeledGroupNode"
127+
? `Stage ${getStageIndex()}`
128+
: `Process ${getProcessIndex()}`,
129+
},
114130
};
115131

116132
if (type === "LabeledGroupNode") {
@@ -189,34 +205,14 @@ export default function Page() {
189205
// Add the new node to the state
190206
setNodes((nds) => nds.concat(newNode));
191207
},
192-
[screenToFlowPosition, type, nodes, setNodes],
193-
);
194-
195-
const onNodesDelete = useCallback(
196-
(deleted) => {
197-
setEdges(
198-
deleted.reduce((acc, node) => {
199-
const incomers = getIncomers(node, nodes, edges);
200-
const outgoers = getOutgoers(node, nodes, edges);
201-
const connectedEdges = getConnectedEdges([node], edges);
202-
203-
const remainingEdges = acc.filter(
204-
(edge) => !connectedEdges.includes(edge),
205-
);
206-
207-
const createdEdges = incomers.flatMap(({ id: source }) =>
208-
outgoers.map(({ id: target }) => ({
209-
id: `${source}->${target}`,
210-
source,
211-
target,
212-
})),
213-
);
214-
215-
return [...remainingEdges, ...createdEdges];
216-
}, edges),
217-
);
218-
},
219-
[nodes, edges],
208+
[
209+
screenToFlowPosition,
210+
type,
211+
nodes,
212+
setNodes,
213+
getStageIndex,
214+
getProcessIndex,
215+
],
220216
);
221217

222218
return (
@@ -228,7 +224,6 @@ export default function Page() {
228224
onNodesChange={onNodesChange}
229225
onEdgesChange={onEdgesChange}
230226
onConnect={onConnect}
231-
onNodesDelete={onNodesDelete}
232227
defaultEdgeOptions={defaultEdgeOptions}
233228
onDrop={onDrop}
234229
onDragOver={onDragOver}

components/labeled-group-node.tsx

+62-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1-
import { Handle, NodeResizeControl, Position } from "@xyflow/react";
1+
import {
2+
Handle,
3+
NodeResizeControl,
4+
Position,
5+
useReactFlow,
6+
} from "@xyflow/react";
27
import { BaseNode } from "@/components/base-node";
8+
import { useEffect, useRef, useState } from "react";
39

410
export function LabeledGroupNode({ id, data, selected }: any) {
511
const { label } = data;
12+
const [isEditing, setIsEditing] = useState(true); // Initially true for newly created nodes
13+
const inputRef = useRef<HTMLInputElement>(null); // Ref for the input element
14+
const { updateNodeData } = useReactFlow();
15+
16+
useEffect(() => {
17+
if (isEditing && inputRef.current) {
18+
// Add a small delay to ensure DOM readiness
19+
setTimeout(() => {
20+
inputRef.current?.focus(); // Focus input when editing starts
21+
}, 0);
22+
}
23+
}, [isEditing]);
624

725
return (
826
<BaseNode
@@ -11,13 +29,54 @@ export function LabeledGroupNode({ id, data, selected }: any) {
1129
width: 600,
1230
height: 300,
1331
}}
32+
onDoubleClick={() => {
33+
if (!isEditing) {
34+
setIsEditing(true); // Enable editing on click
35+
}
36+
}}
1437
>
1538
<NodeResizeControl minWidth={400} minHeight={250}>
1639
<ResizeIcon />
1740
</NodeResizeControl>
1841
{label && (
19-
<div className="absolute -top-7 flex w-full items-end justify-between">
20-
<span className="text-sm font-bold">{label}</span>
42+
<div className="absolute -top-8 flex w-full items-end justify-between">
43+
{isEditing ? (
44+
<input
45+
ref={inputRef}
46+
defaultValue={label}
47+
placeholder="Enter Stage Name"
48+
className="w-full max-w-64 px-2 py-1 text-sm font-bold focus-visible:rounded-md focus-visible:outline-1 focus-visible:outline-primary/50"
49+
onBlur={(evt) => {
50+
const updatedText =
51+
evt.target.value === ""
52+
? "Stage"
53+
: evt.target.value;
54+
updateNodeData(id, { label: updatedText }); // Update node data
55+
setIsEditing(false); // Exit editing mode on blur
56+
}}
57+
onKeyDown={(evt) => {
58+
if (evt.key === "Enter") {
59+
const updatedText =
60+
evt.currentTarget.value === ""
61+
? "Stage"
62+
: evt.currentTarget.value;
63+
updateNodeData(id, { label: updatedText }); // Update node data on Enter
64+
setIsEditing(false); // Exit editing mode
65+
}
66+
}}
67+
/>
68+
) : (
69+
<span
70+
onClick={() => {
71+
if (!isEditing) {
72+
setIsEditing(true); // Enable editing on click
73+
}
74+
}}
75+
className="max-w-60 cursor-pointer truncate px-2 py-1 text-sm font-bold"
76+
>
77+
{label}
78+
</span>
79+
)}
2180
</div>
2281
)}
2382
<Handle type="target" position={Position.Left} />

app/favicon.ico public/favicon.ico

File renamed without changes.

0 commit comments

Comments
 (0)