+
+ getWrappedNode(node, edges, hoveredNodeId))}
+ nodesDraggable={false}
+ edges={edges.map((edge) => ({ ...edge, ...getEdgeProps(edge, hoveredNodeId) }))}
+ onNodeMouseEnter={onNodeMouseEnter}
+ onNodeMouseLeave={onNodeMouseLeave}
+ onNodesChange={onNodesChange}
+ onEdgesChange={onEdgesChange}
+ style={{ height: "100%", width: "100%" }}
+ fitView
+ >
+
+
+
+
+
+ );
+}
+
+function getNodeStyle(node: ZainoRoadmapNode, edges: ZainoRoadmapEdge[], hoveredNodeId: string | null) {
+ const isHovered = node.id === hoveredNodeId;
+ const isParentOrChild = edges.some(
+ (edge) => (edge.source === hoveredNodeId && edge.target === node.id) ||
+ (edge.source === node.id && edge.target === hoveredNodeId)
+ );
+ const normalState: CSSProperties = {
+ fill: "white",
+ stroke: "black",
+ border: "2px solid transparent",
+ borderRadius: "5px",
+ strokeWidth: 1,
+ opacity: 1,
+ };
+ const selectedState: CSSProperties = {
+ fill: "white",
+ border: "2px solid green",
+ borderRadius: "5px",
+ strokeWidth: 2,
+ opacity: 1,
+ };
+ const dimmedState: CSSProperties = {
+ fill: "white",
+ stroke: "black",
+ border: "2px solid transparent",
+ borderRadius: "5px",
+ opacity: 0.2,
+ };
+
+ if (!hoveredNodeId) return normalState;
+
+ return isHovered || isParentOrChild ? selectedState : dimmedState;
+}
+
+function getWrappedNode(node: ZainoRoadmapNode, edges: ZainoRoadmapEdge[], hoveredNodeId: string | null) : WrappedNode {
+ return {
+ ...node,
+ style: { ...node.style, ...getNodeStyle(node, edges, hoveredNodeId) },
+ data: { ...node.data, style: node.style || {} },
+ type: "custom",
+ };
+}
+
+export type WrappedNode = ZainoRoadmapNode & { style: CSSProperties , data: ZainoRoadmapNode['data'] & { style: CSSProperties } };
+
+
+function getEdgeProps(edge: ZainoRoadmapEdge, hoveredNodeId: string | null) {
+ const isParentOrChild = edge.source === hoveredNodeId || edge.target === hoveredNodeId;
+ const normalState: Partial