80 lines
3.3 KiB
TypeScript
80 lines
3.3 KiB
TypeScript
import type { DragEvent as ReactDragEvent, MouseEvent as ReactMouseEvent } from "react";
|
|
import { ExplorerTree, type ExplorerTreeNodeContext } from "@govoplan/core-webui";
|
|
import type { FolderNode } from "../types";
|
|
import { normalizeFolder, treeNodeKey } from "../utils/fileManagerUtils";
|
|
|
|
type FileActionTarget = { spaceId: string; folderPath: string };
|
|
|
|
export function FolderTree({
|
|
nodes,
|
|
activeSpaceId,
|
|
spaceId,
|
|
currentFolder,
|
|
dropTargetKey = "",
|
|
expandedKeys,
|
|
onOpen,
|
|
onToggle,
|
|
onContextMenu,
|
|
onDragOverTarget,
|
|
onDropOnTarget,
|
|
onClearDropState,
|
|
onRequestDragExpand,
|
|
onDragStartFolder,
|
|
onDragEndFolder,
|
|
dragDropEnabled = true,
|
|
contextMenuEnabled = true,
|
|
disabled,
|
|
depth = 1
|
|
}: {
|
|
nodes: FolderNode[];
|
|
activeSpaceId: string;
|
|
spaceId: string;
|
|
currentFolder: string;
|
|
dropTargetKey?: string;
|
|
expandedKeys: Set<string>;
|
|
onOpen: (spaceId: string, path: string) => void;
|
|
onToggle: (spaceId: string, path: string) => void;
|
|
onContextMenu?: (event: ReactMouseEvent<HTMLElement>, spaceId: string, path: string) => void;
|
|
onDragOverTarget?: (event: ReactDragEvent<HTMLElement>, target: FileActionTarget) => void;
|
|
onDropOnTarget?: (event: ReactDragEvent<HTMLElement>, target: FileActionTarget) => Promise<void>;
|
|
onClearDropState?: () => void;
|
|
onRequestDragExpand?: (spaceId: string, path: string) => void;
|
|
onDragStartFolder?: (spaceId: string, path: string, event: ReactDragEvent<HTMLElement>) => void;
|
|
onDragEndFolder?: () => void;
|
|
dragDropEnabled?: boolean;
|
|
contextMenuEnabled?: boolean;
|
|
disabled?: boolean;
|
|
depth?: number;
|
|
}) {
|
|
return (
|
|
<ExplorerTree
|
|
nodes={nodes}
|
|
getNodeId={(node) => treeNodeKey(spaceId, node.path)}
|
|
getNodeLabel={(node) => node.name}
|
|
getNodeChildren={(node) => node.children}
|
|
activeId={activeSpaceId === spaceId ? treeNodeKey(spaceId, currentFolder) : ""}
|
|
expandedIds={expandedKeys}
|
|
onOpen={(node) => onOpen(spaceId, node.path)}
|
|
onToggle={(node) => onToggle(spaceId, node.path)}
|
|
disabled={disabled}
|
|
depth={depth}
|
|
getNodeWrapClassName={(node) => {
|
|
const target = { spaceId, folderPath: node.path };
|
|
return dragDropEnabled && dropTargetKey === `${target.spaceId}:${normalizeFolder(target.folderPath)}` ? "is-drop-target" : undefined;
|
|
}}
|
|
getNodeWrapStyle={(_node, context: ExplorerTreeNodeContext) => ({ paddingLeft: `${Math.min(context.depth * 14, 56)}px` })}
|
|
getNodeDraggable={() => dragDropEnabled && !disabled}
|
|
onContextMenu={contextMenuEnabled && onContextMenu ? (event, node) => onContextMenu(event, spaceId, node.path) : undefined}
|
|
onDragStart={dragDropEnabled && onDragStartFolder ? (event, node) => onDragStartFolder(spaceId, node.path, event) : undefined}
|
|
onDragEnd={dragDropEnabled && onDragEndFolder ? () => onDragEndFolder() : undefined}
|
|
onDragOver={dragDropEnabled && onDragOverTarget ? (event, node, context) => {
|
|
const target = { spaceId, folderPath: node.path };
|
|
onDragOverTarget(event, target);
|
|
if (context.hasChildren && !context.expanded) onRequestDragExpand?.(spaceId, node.path);
|
|
} : undefined}
|
|
onDragLeave={dragDropEnabled && onClearDropState ? () => onClearDropState() : undefined}
|
|
onDrop={dragDropEnabled && onDropOnTarget ? (event, node) => void onDropOnTarget(event, { spaceId, folderPath: node.path }) : undefined}
|
|
/>
|
|
);
|
|
}
|