import { Folder, FolderOpen } from "lucide-react"; import type { CSSProperties, DragEvent as ReactDragEvent, MouseEvent as ReactMouseEvent, ReactNode } from "react"; import { i18nMessage } from "../i18n/LanguageContext"; export type ExplorerTreeNodeContext = { depth: number; active: boolean; expanded: boolean; hasChildren: boolean; disabled: boolean; }; export type ExplorerTreeProps = { nodes: T[]; getNodeId: (node: T) => string; getNodeLabel: (node: T) => string; getNodeChildren: (node: T) => T[]; activeId?: string; expandedIds: Set; onOpen: (node: T, context: ExplorerTreeNodeContext) => void; onToggle: (node: T, context: ExplorerTreeNodeContext) => void; disabled?: boolean; depth?: number; className?: string; childrenBaseClassName?: string; nodeContainerClassName?: string; nodeWrapBaseClassName?: string; toggleBaseClassName?: string; nodeButtonBaseClassName?: string; renderToggleIcon?: (node: T, context: ExplorerTreeNodeContext) => ReactNode; renderNodeContent?: (node: T, context: ExplorerTreeNodeContext) => ReactNode; getNodeWrapClassName?: (node: T, context: ExplorerTreeNodeContext) => string | undefined; getNodeWrapStyle?: (node: T, context: ExplorerTreeNodeContext) => CSSProperties | undefined; getNodeButtonClassName?: (node: T, context: ExplorerTreeNodeContext) => string | undefined; getNodeDraggable?: (node: T, context: ExplorerTreeNodeContext) => boolean; onContextMenu?: (event: ReactMouseEvent, node: T, context: ExplorerTreeNodeContext) => void; onDragStart?: (event: ReactDragEvent, node: T, context: ExplorerTreeNodeContext) => void; onDragEnd?: (event: ReactDragEvent, node: T, context: ExplorerTreeNodeContext) => void; onDragOver?: (event: ReactDragEvent, node: T, context: ExplorerTreeNodeContext) => void; onDragLeave?: (event: ReactDragEvent, node: T, context: ExplorerTreeNodeContext) => void; onDrop?: (event: ReactDragEvent, node: T, context: ExplorerTreeNodeContext) => void; }; export default function ExplorerTree({ nodes, getNodeId, getNodeLabel, getNodeChildren, activeId = "", expandedIds, onOpen, onToggle, disabled = false, depth = 1, className = "", childrenBaseClassName = "explorer-tree-children file-tree-children", nodeContainerClassName = "", nodeWrapBaseClassName = "explorer-tree-node-wrap file-tree-node-wrap", toggleBaseClassName = "explorer-tree-toggle file-tree-toggle", nodeButtonBaseClassName = "explorer-tree-node file-tree-node", renderToggleIcon, renderNodeContent, getNodeWrapClassName, getNodeWrapStyle, getNodeButtonClassName, getNodeDraggable, onContextMenu, onDragStart, onDragEnd, onDragOver, onDragLeave, onDrop }: ExplorerTreeProps) { if (nodes.length === 0) return null; return (
{nodes.map((node) => { const nodeId = getNodeId(node); const children = getNodeChildren(node); const hasChildren = children.length > 0; const expanded = expandedIds.has(nodeId); const active = activeId === nodeId; const context: ExplorerTreeNodeContext = { depth, active, expanded, hasChildren, disabled }; const draggable = getNodeDraggable?.(node, context) ?? false; return (
onContextMenu(event, node, context) : undefined} onDragStart={draggable && onDragStart ? (event) => onDragStart(event, node, context) : undefined} onDragEnd={draggable && onDragEnd ? (event) => onDragEnd(event, node, context) : undefined} onDragOver={onDragOver ? (event) => onDragOver(event, node, context) : undefined} onDragLeave={onDragLeave ? (event) => onDragLeave(event, node, context) : undefined} onDrop={onDrop ? (event) => onDrop(event, node, context) : undefined}>
{hasChildren && expanded && }
); })}
); }