adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
90 lines
2.1 KiB
Svelte
90 lines
2.1 KiB
Svelte
<script lang="ts">
|
|
import FileTree from "./FileTree.svelte";
|
|
import type { FileNode } from "./types";
|
|
import type { SelectData } from "@gradio/utils";
|
|
|
|
interface Props {
|
|
interactive: boolean;
|
|
file_count?: "single" | "multiple";
|
|
value: string[][];
|
|
selectable?: boolean;
|
|
ls_fn: (path: string[]) => Promise<FileNode[]>;
|
|
oninput?: () => void;
|
|
onselect?: (detail: SelectData) => void;
|
|
}
|
|
|
|
let {
|
|
interactive,
|
|
file_count = "multiple",
|
|
value = $bindable(),
|
|
selectable = false,
|
|
ls_fn,
|
|
oninput,
|
|
onselect
|
|
}: Props = $props();
|
|
|
|
let selected_folders = $state<string[][]>([]);
|
|
|
|
const paths_equal = (path: string[], path_2: string[]): boolean => {
|
|
return path.join("/") === path_2.join("/");
|
|
};
|
|
|
|
const path_in_set = (path: string[], set: string[][]): boolean => {
|
|
return set.some((x) => paths_equal(x, path));
|
|
};
|
|
|
|
const path_inside = (path: string[], path_2: string[]): boolean => {
|
|
return path.join("/").startsWith(path_2.join("/"));
|
|
};
|
|
</script>
|
|
|
|
<div class="file-wrap">
|
|
<FileTree
|
|
path={[]}
|
|
selected_files={value}
|
|
{selected_folders}
|
|
{interactive}
|
|
{selectable}
|
|
{ls_fn}
|
|
{file_count}
|
|
valid_for_selection={false}
|
|
oncheck={(detail) => {
|
|
const { path, checked, type } = detail;
|
|
if (checked) {
|
|
if (file_count === "single") {
|
|
value = [path];
|
|
} else if (type === "folder") {
|
|
if (!path_in_set(path, selected_folders)) {
|
|
selected_folders = [...selected_folders, path];
|
|
}
|
|
} else {
|
|
if (!path_in_set(path, value)) {
|
|
value = [...value, path];
|
|
}
|
|
}
|
|
} else {
|
|
selected_folders = selected_folders.filter(
|
|
(folder) => !path_inside(path, folder)
|
|
); // deselect all parent folders
|
|
if (type === "folder") {
|
|
selected_folders = selected_folders.filter(
|
|
(folder) => !path_inside(folder, path)
|
|
); // deselect all children folders
|
|
value = value.filter((file) => !path_inside(file, path)); // deselect all children files
|
|
} else {
|
|
value = value.filter((x) => !paths_equal(x, path));
|
|
}
|
|
}
|
|
oninput?.();
|
|
}}
|
|
{onselect}
|
|
/>
|
|
</div>
|
|
|
|
<style>
|
|
.file-wrap {
|
|
height: calc(100% - 25px);
|
|
overflow-y: scroll;
|
|
}
|
|
</style>
|