import React, { memo, ComponentType } from 'react'; import { useStoreState } from '../../store/hooks'; import { getNodesInside } from '../../utils/graph'; import { Node, Transform, NodeTypesType, WrapNodeProps, Elements, Edge } from '../../types'; interface NodeRendererProps { nodeTypes: NodeTypesType; selectNodesOnDrag: boolean; onElementClick?: (element: Node | Edge) => void; onNodeDragStart?: (node: Node) => void; onNodeDragStop?: (node: Node) => void; onlyRenderVisibleNodes?: boolean; } function renderNode( node: Node, props: NodeRendererProps, transform: Transform, selectedElements: Elements | null, isInteractive: boolean ) { const nodeType = node.type || 'default'; const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType; if (!props.nodeTypes[nodeType]) { console.warn(`Node type "${nodeType}" not found. Using fallback type "default".`); } const isSelected = selectedElements ? selectedElements.some(({ id }) => id === node.id) : false; return ( ); } const NodeRenderer = memo(({ onlyRenderVisibleNodes = true, ...props }: NodeRendererProps) => { const nodes = useStoreState((s) => s.nodes); const transform = useStoreState((s) => s.transform); const selectedElements = useStoreState((s) => s.selectedElements); const width = useStoreState((s) => s.width); const height = useStoreState((s) => s.height); const isInteractive = useStoreState((s) => s.isInteractive); const [tX, tY, tScale] = transform; const transformStyle = { transform: `translate(${tX}px,${tY}px) scale(${tScale})`, }; const renderNodes = onlyRenderVisibleNodes ? getNodesInside(nodes, { x: 0, y: 0, width, height }, transform, true) : nodes; return (
{renderNodes.map((node) => renderNode(node, props, transform, selectedElements, isInteractive))}
); }); NodeRenderer.displayName = 'NodeRenderer'; export default NodeRenderer;