fix: filetree wrong opening order
This commit is contained in:
parent
ac3e2a6b01
commit
eb5fae3ab7
1 changed files with 90 additions and 101 deletions
|
|
@ -32,8 +32,8 @@ interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FileTree = memo(
|
export const FileTree = memo((props: Props) => {
|
||||||
({
|
const {
|
||||||
files = [],
|
files = [],
|
||||||
onFileSelect,
|
onFileSelect,
|
||||||
selectedFile,
|
selectedFile,
|
||||||
|
|
@ -41,118 +41,107 @@ export const FileTree = memo(
|
||||||
expandedFolders = new Set(),
|
expandedFolders = new Set(),
|
||||||
loadingFolders = new Set(),
|
loadingFolders = new Set(),
|
||||||
className,
|
className,
|
||||||
}: Props) => {
|
} = props;
|
||||||
const fileList = useMemo(() => {
|
|
||||||
return buildFileList(files);
|
|
||||||
}, [files]);
|
|
||||||
|
|
||||||
const [collapsedFolders, setCollapsedFolders] = useState<Set<string>>(new Set());
|
const fileList = useMemo(() => {
|
||||||
|
return buildFileList(files);
|
||||||
|
}, [files]);
|
||||||
|
|
||||||
const filteredFileList = useMemo(() => {
|
const [collapsedFolders, setCollapsedFolders] = useState<Set<string>>(new Set());
|
||||||
const list = [];
|
|
||||||
let lastDepth = Number.MAX_SAFE_INTEGER;
|
|
||||||
|
|
||||||
for (const fileOrFolder of fileList) {
|
const filteredFileList = useMemo(() => {
|
||||||
const depth = fileOrFolder.depth;
|
const list = [];
|
||||||
|
let lastDepth = Number.MAX_SAFE_INTEGER;
|
||||||
|
|
||||||
// if the depth is equal we reached the end of the collapsed group
|
for (const fileOrFolder of fileList) {
|
||||||
if (lastDepth === depth) {
|
const depth = fileOrFolder.depth;
|
||||||
lastDepth = Number.MAX_SAFE_INTEGER;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore collapsed folders
|
// if the depth is equal we reached the end of the collapsed group
|
||||||
if (collapsedFolders.has(fileOrFolder.fullPath)) {
|
if (lastDepth === depth) {
|
||||||
lastDepth = Math.min(lastDepth, depth);
|
lastDepth = Number.MAX_SAFE_INTEGER;
|
||||||
}
|
|
||||||
|
|
||||||
// ignore files and folders below the last collapsed folder
|
|
||||||
if (lastDepth < depth) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.push(fileOrFolder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
// ignore collapsed folders
|
||||||
}, [fileList, collapsedFolders]);
|
if (collapsedFolders.has(fileOrFolder.fullPath)) {
|
||||||
|
lastDepth = Math.min(lastDepth, depth);
|
||||||
|
}
|
||||||
|
|
||||||
const toggleCollapseState = (fullPath: string) => {
|
// ignore files and folders below the last collapsed folder
|
||||||
setCollapsedFolders((prevSet) => {
|
if (lastDepth < depth) {
|
||||||
const newSet = new Set(prevSet);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (newSet.has(fullPath)) {
|
list.push(fileOrFolder);
|
||||||
newSet.delete(fullPath);
|
}
|
||||||
onFolderExpand?.(fullPath);
|
|
||||||
} else {
|
return list;
|
||||||
newSet.add(fullPath);
|
}, [fileList, collapsedFolders]);
|
||||||
|
|
||||||
|
const toggleCollapseState = (fullPath: string) => {
|
||||||
|
setCollapsedFolders((prevSet) => {
|
||||||
|
const newSet = new Set(prevSet);
|
||||||
|
|
||||||
|
if (newSet.has(fullPath)) {
|
||||||
|
newSet.delete(fullPath);
|
||||||
|
onFolderExpand?.(fullPath);
|
||||||
|
} else {
|
||||||
|
newSet.add(fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add new folders to collapsed set when file list changes
|
||||||
|
useEffect(() => {
|
||||||
|
setCollapsedFolders((prevSet) => {
|
||||||
|
const newSet = new Set(prevSet);
|
||||||
|
for (const item of fileList) {
|
||||||
|
if (item.kind === "folder" && !newSet.has(item.fullPath) && !expandedFolders.has(item.fullPath)) {
|
||||||
|
newSet.add(item.fullPath);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
}, [fileList, expandedFolders]);
|
||||||
|
|
||||||
return newSet;
|
return (
|
||||||
});
|
<div className={cn("text-sm", className)}>
|
||||||
};
|
{filteredFileList.map((fileOrFolder) => {
|
||||||
|
switch (fileOrFolder.kind) {
|
||||||
// Add new folders to collapsed set when file list changes
|
case "file": {
|
||||||
useEffect(() => {
|
return (
|
||||||
setCollapsedFolders((prevSet) => {
|
<File
|
||||||
const newSet = new Set(prevSet);
|
key={fileOrFolder.id}
|
||||||
for (const item of fileList) {
|
selected={selectedFile === fileOrFolder.fullPath}
|
||||||
if (item.kind === "folder" && !newSet.has(item.fullPath) && !expandedFolders.has(item.fullPath)) {
|
file={fileOrFolder}
|
||||||
newSet.add(item.fullPath);
|
onClick={() => {
|
||||||
|
onFileSelect?.(fileOrFolder.fullPath);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "folder": {
|
||||||
|
return (
|
||||||
|
<Folder
|
||||||
|
key={fileOrFolder.id}
|
||||||
|
folder={fileOrFolder}
|
||||||
|
collapsed={collapsedFolders.has(fileOrFolder.fullPath)}
|
||||||
|
loading={loadingFolders.has(fileOrFolder.fullPath)}
|
||||||
|
onClick={() => {
|
||||||
|
toggleCollapseState(fileOrFolder.fullPath);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newSet;
|
})}
|
||||||
});
|
</div>
|
||||||
}, [fileList, expandedFolders]);
|
);
|
||||||
|
});
|
||||||
// Expand folders that are in the expandedFolders set
|
|
||||||
useEffect(() => {
|
|
||||||
setCollapsedFolders((prevSet) => {
|
|
||||||
const newSet = new Set(prevSet);
|
|
||||||
for (const folder of expandedFolders) {
|
|
||||||
newSet.delete(folder);
|
|
||||||
}
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
}, [expandedFolders]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={cn("text-sm", className)}>
|
|
||||||
{filteredFileList.map((fileOrFolder) => {
|
|
||||||
switch (fileOrFolder.kind) {
|
|
||||||
case "file": {
|
|
||||||
return (
|
|
||||||
<File
|
|
||||||
key={fileOrFolder.id}
|
|
||||||
selected={selectedFile === fileOrFolder.fullPath}
|
|
||||||
file={fileOrFolder}
|
|
||||||
onClick={() => {
|
|
||||||
onFileSelect?.(fileOrFolder.fullPath);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case "folder": {
|
|
||||||
return (
|
|
||||||
<Folder
|
|
||||||
key={fileOrFolder.id}
|
|
||||||
folder={fileOrFolder}
|
|
||||||
collapsed={collapsedFolders.has(fileOrFolder.fullPath)}
|
|
||||||
loading={loadingFolders.has(fileOrFolder.fullPath)}
|
|
||||||
onClick={() => {
|
|
||||||
toggleCollapseState(fileOrFolder.fullPath);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
interface FolderProps {
|
interface FolderProps {
|
||||||
folder: FolderNode;
|
folder: FolderNode;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue