Files
bea-edit/src/lib/components/ZipFilePicker.svelte
T
2026-10-06 22:52:35 +02:00

63 lines
1.5 KiB
Svelte

<script lang="ts">
import Button from '$lib/components/ui/button.svelte';
import type { ButtonVariant } from '$lib/components/ui/button.svelte';
import { isAcceptedWorkspaceFile, WORKSPACE_ACCEPT_TYPES } from '$lib/zip-selection';
import type { Snippet } from 'svelte';
type Props = {
/** Identifies the hidden input for tests, e.g. `replace-zip` or `append-zip`. */
pickerId: string;
ariaLabel: string;
onFilesSelected: (files: File[]) => void;
children: Snippet;
multiple?: boolean;
disabled?: boolean;
variant?: ButtonVariant;
class?: string;
};
let {
pickerId,
ariaLabel,
onFilesSelected,
children,
multiple = true,
disabled = false,
variant = 'primary',
class: className = ''
}: Props = $props();
let fileInput = $state<HTMLInputElement | null>(null);
const handleFileSelection = (event: Event) => {
const input = event.currentTarget as HTMLInputElement;
const files = Array.from(input.files ?? []).filter(isAcceptedWorkspaceFile);
// Reset first so selecting the same file again still fires `change`.
input.value = '';
if (files.length === 0) return;
onFilesSelected(multiple ? files : files.slice(0, 1));
};
</script>
<input
bind:this={fileInput}
class="hidden"
type="file"
accept={WORKSPACE_ACCEPT_TYPES}
{multiple}
data-zip-picker={pickerId}
onchange={handleFileSelection}
/>
<Button
{variant}
{disabled}
aria-label={ariaLabel}
class={className}
onclick={() => fileInput?.click()}
>
{@render children()}
</Button>