import { memo, useCallback, type MouseEvent as ReactMouseEvent, type ReactNode } from 'react' import { CaretDown, CaretRight, Folder, FolderOpen, PencilSimple, Trash, } from '@phosphor-icons/react' import { Button } from '@/components/ui/button' import { cn } from '@/lib/utils' import type { FolderNode, SidebarSelection } from '../../types' import { FolderNameInput } from './FolderNameInput' interface FolderTreeRowProps { depth: number expanded: Record node: FolderNode onDeleteFolder?: (folderPath: string) => void onOpenMenu: (node: FolderNode, event: ReactMouseEvent) => void onRenameFolder?: (folderPath: string, nextName: string) => Promise | boolean onSelect: (selection: SidebarSelection) => void onStartRenameFolder?: (folderPath: string) => void onToggle: (path: string) => void onCancelRenameFolder?: () => void renamingFolderPath?: string | null selection: SidebarSelection } function FolderRenameRow({ indentation, node, onCancelRenameFolder, onRenameFolder, }: { indentation: number node: FolderNode onCancelRenameFolder: () => void onRenameFolder: (folderPath: string, nextName: string) => Promise | boolean }) { return (
onRenameFolder(node.path, nextName)} />
) } function FolderItemRow({ indentation, isExpanded, isSelected, node, onDeleteFolder, onOpenMenu, onSelect, onStartRenameFolder, onToggle, }: { indentation: number isExpanded: boolean isSelected: boolean node: FolderNode onDeleteFolder?: (folderPath: string) => void onOpenMenu: FolderTreeRowProps['onOpenMenu'] onSelect: () => void onStartRenameFolder?: (folderPath: string) => void onToggle: (path: string) => void }) { const hasChildren = node.children.length > 0 const expandLabel = isExpanded ? `Collapse ${node.name}` : `Expand ${node.name}` const hasActions = !!onStartRenameFolder || !!onDeleteFolder return (
{ onSelect() onOpenMenu(node, event) }} > onToggle(node.path)} /> {hasActions && (
{onStartRenameFolder && ( { onSelect() onStartRenameFolder(node.path) }} > )} {onDeleteFolder && ( { onSelect() onDeleteFolder(node.path) }} > )}
)}
) } function FolderToggleButton({ expandLabel, hasChildren, isExpanded, onToggle, }: { expandLabel: string hasChildren: boolean isExpanded: boolean onToggle: () => void }) { return ( ) } function FolderActionButton({ ariaLabel, children, destructive = false, onClick, testId, title, }: { ariaLabel: string children: ReactNode destructive?: boolean onClick: () => void testId: string title: string }) { return ( ) } function FolderSelectButton({ hasActions, isExpanded, isSelected, node, onSelect, onStartRenameFolder, }: { hasActions: boolean isExpanded: boolean isSelected: boolean node: FolderNode onSelect: () => void onStartRenameFolder?: (folderPath: string) => void }) { return ( ) } function FolderChildren({ depth, expanded, node, onDeleteFolder, onOpenMenu, onRenameFolder, onSelect, onStartRenameFolder, onToggle, onCancelRenameFolder, renamingFolderPath, selection, }: FolderTreeRowProps) { const isExpanded = expanded[node.path] ?? false const hasChildren = node.children.length > 0 if (!isExpanded || !hasChildren) return null return (
{node.children.map((child) => ( ))}
) } export const FolderTreeRow = memo(function FolderTreeRow({ depth, expanded, node, onDeleteFolder, onOpenMenu, onRenameFolder, onSelect, onStartRenameFolder, onToggle, onCancelRenameFolder, renamingFolderPath, selection, }: FolderTreeRowProps) { const isExpanded = expanded[node.path] ?? false const isRenaming = renamingFolderPath === node.path const isSelected = selection.kind === 'folder' && selection.path === node.path const indentation = 8 + depth * 16 const selectFolder = useCallback(() => { onSelect({ kind: 'folder', path: node.path }) }, [node.path, onSelect]) return ( <> {isRenaming && onRenameFolder && onCancelRenameFolder ? ( ) : ( )} ) })