import React, { useRef, useState } from 'react'; import { Box } from '@mantine/core'; import { Tree, type NodeApi } from 'react-arborist'; import { IconFolder, IconFolderOpen, IconChevronRight, } from '@tabler/icons-react'; import useResizeObserver from '@react-hook/resize-observer'; import { filterToFolders } from '../../utils/fileTreeUtils'; import type { FileNode } from '@/types/models'; interface FolderSelectorProps { files: FileNode[]; selectedPath: string; onSelect: (path: string) => void; } interface Size { width: number; height: number; } const useSize = ( target: React.RefObject ): Size | undefined => { const [size, setSize] = useState(); useResizeObserver(target, (entry) => setSize(entry.contentRect)); return size; }; // Node component for rendering folders function FolderNode({ node, style, selectedPath, onSelect, }: { node: NodeApi; style: React.CSSProperties; selectedPath: string; onSelect: (path: string) => void; }) { const isSelected = node.data.path === selectedPath; const hasChildren = node.children && node.children.length > 0; const handleClick = () => { onSelect(node.data.path); }; const handleChevronClick = (e: React.MouseEvent) => { e.stopPropagation(); node.toggle(); }; return (
{ if (!isSelected) { e.currentTarget.style.backgroundColor = 'var(--mantine-color-default-hover)'; } }} onMouseLeave={(e) => { if (!isSelected) { e.currentTarget.style.backgroundColor = 'transparent'; } }} > {/* Chevron for folders with children */} {hasChildren && ( )} {/* Spacer for items without chevron */} {!hasChildren &&
} {/* Folder icon */} {node.isOpen ? ( ) : ( )} {/* Name */} {node.data.name}
); } // Root node component function RootNode({ isSelected, onSelect, }: { isSelected: boolean; onSelect: () => void; }) { return (
{ if (!isSelected) { e.currentTarget.style.backgroundColor = 'var(--mantine-color-default-hover)'; } }} onMouseLeave={(e) => { if (!isSelected) { e.currentTarget.style.backgroundColor = 'transparent'; } }} >
/ (root)
); } export const FolderSelector: React.FC = ({ files, selectedPath, onSelect, }) => { const target = useRef(null); const size = useSize(target); // Filter to only folders const folders = filterToFolders(files); // Calculate tree height: root node (32px) + folders const rootNodeHeight = 32; const treeHeight = size ? size.height - rootNodeHeight : 0; return ( {/* Root option */} onSelect('')} /> {/* Folder tree */} {size && folders.length > 0 && ( true} disableDrop={() => true} > {(props) => ( )} )} ); }; export default FolderSelector;