import React, { useCallback, useRef, useState } from "react" import { cn } from "@/lib/utils" import type { CompositeNode, NodePort } from "../../types/node-compositing" import { NodeParameterControl } from "./node-parameter-control" interface NodeComponentProps { node: CompositeNode selected: boolean onMove: (x: number, y: number) => void onPortClick: (portId: string, isOutput: boolean, position: { x: number; y: number }) => void onParameterChange: (parameterId: string, value: any) => void onSelect: () => void } export function NodeComponent({ node, selected, onMove, onPortClick, onParameterChange, onSelect, }: NodeComponentProps) { const nodeRef = useRef(null) const [isDragging, setIsDragging] = useState(false) const [isExpanded, setIsExpanded] = useState(true) const [dragStart, setDragStart] = useState({ x: 0, y: 0 }) // Handle node dragging const handleMouseDown = useCallback( (e: React.MouseEvent) => { if (e.target === nodeRef.current || (e.target as HTMLElement).classList.contains("node-header")) { e.preventDefault() e.stopPropagation() setIsDragging(true) setDragStart({ x: e.clientX - node.position.x, y: e.clientY - node.position.y, }) onSelect() } }, [node.position, onSelect], ) const handleMouseMove = useCallback( (e: MouseEvent) => { if (isDragging) { const newX = e.clientX - dragStart.x const newY = e.clientY - dragStart.y onMove(newX, newY) } }, [isDragging, dragStart, onMove], ) const handleMouseUp = useCallback(() => { setIsDragging(false) }, []) // Setup global mouse listeners for dragging React.useEffect(() => { if (isDragging) { window.addEventListener("mousemove", handleMouseMove) window.addEventListener("mouseup", handleMouseUp) return () => { window.removeEventListener("mousemove", handleMouseMove) window.removeEventListener("mouseup", handleMouseUp) } } }, [isDragging, handleMouseMove, handleMouseUp]) // Handle port clicks const handlePortClick = (port: NodePort, isOutput: boolean) => (e: React.MouseEvent) => { e.stopPropagation() const portElement = e.currentTarget as HTMLElement const rect = portElement.getBoundingClientRect() const nodeRect = nodeRef.current!.getBoundingClientRect() onPortClick(port.id, isOutput, { x: rect.left + rect.width / 2 - nodeRect.left + node.position.x, y: rect.top + rect.height / 2 - nodeRect.top + node.position.y, }) } // Get node color based on category const getCategoryColor = () => { switch (node.category) { case "source": return "from-green-600 to-green-700" case "filter": return "from-blue-600 to-blue-700" case "transform": return "from-purple-600 to-purple-700" case "composite": return "from-orange-600 to-orange-700" case "color": return "from-pink-600 to-pink-700" case "output": return "from-red-600 to-red-700" default: return "from-gray-600 to-gray-700" } } return (
{/* Header */}
{node.name}
{/* Content */}
{/* Input ports */}
{node.inputs.map((port) => (
{port.name}
))}
{/* Parameters */} {node.parameters.length > 0 && (
{node.parameters.map((param) => ( onParameterChange(param.id, value)} /> ))}
)} {/* Output ports */}
{node.outputs.map((port) => (
{port.name}
))}
{/* Preview */} {node.preview && (
Preview
)} {/* Error message */} {node.error && (
{node.error}
)} {/* Processing indicator */} {node.processing && (
)}
) }