/** * CanvasNode Component * Renders a workflow node on the canvas with input/output ports */ 'use client'; import React, { MouseEvent } from 'react'; import type { WorkflowNode, NodeType, Position } from './types'; import { getNodeIcon } from './icons'; import styles from '../../scss/atoms/workflow-editor.module.scss'; export interface CanvasNodeProps { node: WorkflowNode; nodeType: NodeType | undefined; isSelected: boolean; onSelect: (id: string) => void; onDoubleClick: (id: string) => void; onDragStart: (e: MouseEvent, nodeId: string) => void; onConnectionStart: (nodeId: string, outputName: string, position: Position) => void; onConnectionEnd: (nodeId: string, inputName: string) => void; isDrawingConnection: boolean; } export function CanvasNode({ node, nodeType, isSelected, onSelect, onDoubleClick, onDragStart, onConnectionStart, onConnectionEnd, isDrawingConnection, }: CanvasNodeProps): React.ReactElement { const color = nodeType?.color || '#666'; return (
onSelect(node.id)} onDoubleClick={() => onDoubleClick(node.id)} onMouseDown={(e: MouseEvent) => { if ((e.target as HTMLElement).classList.contains(styles.outputPort)) return; if ((e.target as HTMLElement).classList.contains(styles.inputPort)) return; onDragStart(e, node.id); }} className={`${styles.canvasNode} ${isSelected ? styles.selected : ''}`} style={{ left: node.position.x, top: node.position.y }} >

{node.name}

{nodeType?.description || 'Custom node'}

{/* Input Ports */} {node.inputs.map((input, idx) => (
{ if (isDrawingConnection) { onConnectionEnd(node.id, input); } }} /> ))} {/* Output Ports */} {node.outputs.map((output, idx) => (
) => { e.stopPropagation(); onConnectionStart(node.id, output, { x: node.position.x + 200 + 8, y: node.position.y + 80 + idx * 24 + 8, }); }} style={{ top: 80 + idx * 24, backgroundColor: color, color }} title={`Output: ${output}`} /> ))}
); }