import React, { useState } from 'react'; import type { TreeNode } from '../types/ui.types'; interface TreeViewProps { nodes: TreeNode[]; selectedId?: string | null; onSelect: (id: string) => void; onToggle?: (id: string) => void; renderIcon?: (node: TreeNode) => React.ReactNode; renderActions?: (node: TreeNode) => React.ReactNode; renderDetail?: (node: TreeNode) => React.ReactNode; draggable?: boolean; } const TreeView: React.FC = ({ nodes, selectedId, onSelect, onToggle, renderIcon, renderActions, renderDetail, draggable = false, }) => { const [expandedSet, setExpandedSet] = useState>(new Set()); const toggleExpand = (id: string) => { setExpandedSet((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); onToggle?.(id); }; const renderNode = (node: TreeNode, level: number): React.ReactNode => { const hasChildren = node.children && node.children.length > 0; const isExpanded = expandedSet.has(node.id) || node.expanded; const isSelected = selectedId === node.id; return (
onSelect(node.id)} draggable={draggable} > {hasChildren && ( )} {!hasChildren && } {renderIcon && {renderIcon(node)}} {node.name} {node.count !== undefined && ({node.count})} {renderActions && e.stopPropagation()}>{renderActions(node)}}
{renderDetail && isSelected && (
{renderDetail(node)}
)} {hasChildren && isExpanded && (
{node.children!.map((child) => renderNode(child, level + 1))}
)}
); }; return
{nodes.map((node) => renderNode(node, 0))}
; }; export default TreeView;