import React, { useState, useRef, useEffect } from 'react' import { Sankey } from 'recharts' import SankeyNode from './SankeyNode' import SankeyLink from './SankeyLink' import { SankeyTooltipData } from './types' import Block from '../Primitives/Block/Block' import Text from '../Text/Text' import { FOUNDATION_THEME } from '../../tokens' import { formatNumber } from './ChartUtils' interface SankeyChartWrapperProps { chartName?: string transformedData: { nodes: { name: string }[] links: { source: number target: number value: number color?: string hoverColor?: string sourceName?: string targetName?: string }[] } nodeColors: string[] linkColors: string[] sankeyWidth: number sankeyHeight: number isSmallScreen: boolean } const SankeyChartWrapper: React.FC = ({ chartName, transformedData, nodeColors, linkColors, sankeyWidth, sankeyHeight, isSmallScreen, }) => { const containerRef = useRef(null) const [containerWidth, setContainerWidth] = useState(sankeyWidth) const [containerHeight, setContainerHeight] = useState(sankeyHeight) const [tooltipData, setTooltipData] = useState( null ) const [tooltipPosition, setTooltipPosition] = useState<{ x: number y: number } | null>(null) useEffect(() => { const updateDimensions = () => { if (containerRef.current) { const width = containerRef.current.offsetWidth const height = containerRef.current.offsetHeight setContainerWidth(Math.max(300, width - 40)) if (height > 100) { setContainerHeight(Math.max(300, height - 40)) } } } updateDimensions() const timeoutId = setTimeout(updateDimensions, 100) window.addEventListener('resize', updateDimensions) return () => { window.removeEventListener('resize', updateDimensions) clearTimeout(timeoutId) } }, [sankeyWidth, sankeyHeight]) const handleMouseEnter = ( data: SankeyTooltipData, event: React.MouseEvent ) => { setTooltipData(data) setTooltipPosition({ x: event.clientX, y: event.clientY, }) } const handleMouseLeave = () => { setTooltipData(null) setTooltipPosition(null) } const renderTooltip = () => { if (!tooltipData || !tooltipPosition) return null const data = tooltipData.payload // Node tooltip if ( data?.name && data?.source === undefined && data?.target === undefined ) { return ( {data.name} {data.value !== undefined && ( Value: {formatNumber(data.value)} )} ) } if ( data?.source !== undefined && data?.target !== undefined && data?.value !== undefined ) { return ( Flow From: {data.sourceName || `Node ${data.source}`} To: {data.targetName || `Node ${data.target}`} Value: {formatNumber(data.value)} ) } return null } const getMargins = () => { if (containerWidth < 500) { return { top: 10, bottom: 10, left: 5, right: 80 } } else if (containerWidth < 800) { return { top: 15, bottom: 15, left: 20, right: 100 } } else if (isSmallScreen) { return { top: 20, bottom: 20, left: 30, right: 120 } } else { return { top: 20, bottom: 20, left: 150, right: 200 } } } const margins = getMargins() return ( <> {containerWidth > 0 && containerHeight > 0 && ( } node={ } > )} {renderTooltip()} ) } export default SankeyChartWrapper