File Upload
原生 <input type="file"> + file:* 工具类(行内)和虚线拖放区(大区域)。Alpine 驱动的多文件进度条 — 进度条动画由模拟进度驱动,演示自运行。
最简 — inline picker (outline)
<x-file-upload color="primary" label="Primary — outline" />
<x-file-upload color="success" label="Success — outline" />
<x-file-upload color="warning" label="Warning — outline" />
<x-file-upload color="error" label="Error — outline" />
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Primary — outline</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-primary focus-within:ring-1 focus-within:ring-primary h-[var(--h-field-md)]">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b762ffbd" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b762ffbd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Success — outline</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-success focus-within:ring-1 focus-within:ring-success h-[var(--h-field-md)]">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b7630029" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-success transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b7630029" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Warning — outline</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-warning focus-within:ring-1 focus-within:ring-warning h-[var(--h-field-md)]">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b763008a" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-warning transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b763008a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Error — outline</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-error focus-within:ring-1 focus-within:ring-error h-[var(--h-field-md)]">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b76300eb" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-error transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b76300eb" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
appearance=soft x color
<x-file-upload appearance="soft" color="primary" label="Primary — soft" />
<x-file-upload appearance="soft" color="success" label="Success — soft" />
<x-file-upload appearance="soft" color="warning" label="Warning — soft" />
<x-file-upload appearance="soft" color="error" label="Error — soft" />
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Primary — soft</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-primary/10 tune-border border-transparent focus-within:ring-1 focus-within:ring-primary h-[var(--h-field-md)]">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b76dfe51" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b76dfe51" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Success — soft</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-success/10 tune-border border-transparent focus-within:ring-1 focus-within:ring-success h-[var(--h-field-md)]">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b76dfebe" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-success transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b76dfebe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Warning — soft</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-warning/10 tune-border border-transparent focus-within:ring-1 focus-within:ring-warning h-[var(--h-field-md)]">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b76dff1d" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-warning transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b76dff1d" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Error — soft</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-error/10 tune-border border-transparent focus-within:ring-1 focus-within:ring-error h-[var(--h-field-md)]">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b76dff7a" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-error transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b76dff7a" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
size — sm / md / lg (inline)
<x-file-upload size="sm" label="size sm" />
<x-file-upload size="md" label="size md (default)" />
<x-file-upload size="lg" label="size lg" />
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">size sm</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-base-300 focus-within:border-primary focus-within:ring-1 focus-within:ring-primary h-[var(--h-field-sm)]">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b779ce32" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-sm)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-3 file:py-1" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-xs)]">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b779ce32" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">size md (default)</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-base-300 focus-within:border-primary focus-within:ring-1 focus-within:ring-primary h-[var(--h-field-md)]">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b779cea5" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b779cea5" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">size lg</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-base-300 focus-within:border-primary focus-within:ring-1 focus-within:ring-primary h-[var(--h-field-lg)]">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b779cf09" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-lg)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-5 file:py-3" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-md)]">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b779cf09" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
appearance=dropzone
<x-file-upload appearance="dropzone" color="primary" label="Cover image" description="PNG, JPG, WebP — max 5MB" accept="image/*" />
<x-file-upload appearance="dropzone" color="success" label="Documents" description="PDF, DOCX — max 10MB" accept=".pdf,.doc,.docx" />
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Cover image</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-primary focus-within:border-primary focus-within:ring-1 focus-within:ring-primary px-6 py-8">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-primary hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/60">PNG, JPG, WebP — max 5MB</small>
<input x-ref="input" type="file" id="file_6a7e9b782e8ea" class="sr-only" @change="onChange($event)" accept="image/*"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b782e8ea" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Documents</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-success focus-within:border-success focus-within:ring-1 focus-within:ring-success px-6 py-8">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-success hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/60">PDF, DOCX — max 10MB</small>
<input x-ref="input" type="file" id="file_6a7e9b782e979" class="sr-only" @change="onChange($event)" accept=".pdf,.doc,.docx"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-success transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b782e979" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
multiple + simulate(模拟上传进度)
<x-file-upload
appearance="dropzone"
color="primary"
label="Documents (horizontal preview)"
description="Each file gets its own row with thumbnail, name, size, progress."
multiple
simulate
/>
<x-file-upload
appearance="outline"
color="info"
label="Inline picker (horizontal preview)"
description="Inline file input, multiple selection, progress runs to 100%."
multiple
simulate
/>
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Documents (horizontal preview)</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-primary focus-within:border-primary focus-within:ring-1 focus-within:ring-primary px-6 py-8">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-primary hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/60">Each file gets its own row with thumbnail, name, size, progress.</small>
<input x-ref="input" type="file" id="file_6a7e9b7894888" class="sr-only" @change="onChange($event)" multiple></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b7894888" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Inline picker (horizontal preview)</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-info focus-within:ring-1 focus-within:ring-info h-[var(--h-field-md)]">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b78948fe" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)" multiple></label>
</div><label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/50">Inline file input, multiple selection, progress runs to 100%.</small></label>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-info transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b78948fe" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
preview-layout=grid — square thumbnails
<x-file-upload
appearance="dropzone"
color="primary"
preview-layout="grid"
label="Photo gallery"
description="Pick several images — preview tiles fill in like a picture-card grid."
accept="image/*"
multiple
simulate
/>
<x-file-upload
appearance="outline"
color="success"
preview-layout="grid"
label="Mixed assets"
description="Images show thumbnails, other types show a generic file icon."
multiple
simulate
/>
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Photo gallery</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-primary focus-within:border-primary focus-within:ring-1 focus-within:ring-primary px-6 py-8">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-primary hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/60">Pick several images — preview tiles fill in like a picture-card grid.</small>
<input x-ref="input" type="file" id="file_6a7e9b7903143" class="sr-only" @change="onChange($event)" accept="image/*" multiple></label>
</div>
<ul class="mt-2 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="group relative aspect-square rounded-[var(--radius-field)] overflow-hidden tune-border border-base-300 bg-base-100">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="absolute inset-0 w-full h-full object-cover" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="absolute inset-0 flex items-center justify-center bg-base-200 text-base-content/40">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template><label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="absolute inset-x-0 bottom-0 px-2 pt-6 pb-2 bg-gradient-to-t from-black/70 via-black/40 to-transparent text-white text-[length:var(--text-field-xs)] truncate" x-text="item.name"></span>
<button type="button" class="absolute top-1.5 right-1.5 size-6 inline-flex items-center justify-center rounded-full bg-black/50 text-white hover:bg-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-3.5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
<div class="absolute bottom-0 inset-x-0 h-1 bg-black/30 overflow-hidden" x-show="!item.complete">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b7903143" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Mixed assets</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-success focus-within:ring-1 focus-within:ring-success h-[var(--h-field-md)]">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b79031c4" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)" multiple></label>
</div><label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/50">Images show thumbnails, other types show a generic file icon.</small></label>
<ul class="mt-2 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="group relative aspect-square rounded-[var(--radius-field)] overflow-hidden tune-border border-base-300 bg-base-100">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="absolute inset-0 w-full h-full object-cover" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="absolute inset-0 flex items-center justify-center bg-base-200 text-base-content/40">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template><label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="absolute inset-x-0 bottom-0 px-2 pt-6 pb-2 bg-gradient-to-t from-black/70 via-black/40 to-transparent text-white text-[length:var(--text-field-xs)] truncate" x-text="item.name"></span>
<button type="button" class="absolute top-1.5 right-1.5 size-6 inline-flex items-center justify-center rounded-full bg-black/50 text-white hover:bg-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-3.5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
<div class="absolute bottom-0 inset-x-0 h-1 bg-black/30 overflow-hidden" x-show="!item.complete">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-success transition-[width] duration-300 ease-out" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b79031c4" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
错误状态
<x-file-upload label="Profile photo" description="JPG / PNG only" error="Required — please choose a file" />
<x-file-upload appearance="dropzone" label="Receipt" description="PDF only" error="Required — please choose a file" />
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-error text-[length:var(--text-field-sm)] font-medium">Profile photo</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-error focus-within:ring-1 focus-within:ring-error h-[var(--h-field-md)]">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b794e0dd" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-error transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b794e0dd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-error">Required — please choose a file</small></label>
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-error text-[length:var(--text-field-sm)] font-medium">Receipt</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-error focus-within:border-error focus-within:ring-1 focus-within:ring-error px-6 py-8">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-error hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/60">PDF only</small>
<input x-ref="input" type="file" id="file_6a7e9b794e14c" class="sr-only" @change="onChange($event)"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-error transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b794e14c" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-error">Required — please choose a file</small></label>
disabled
<x-file-upload label="Disabled (inline)" disabled />
<x-file-upload appearance="dropzone" color="primary" label="Disabled (dropzone)" disabled />
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Disabled (inline)</span></label>
<div class="flex items-stretch overflow-clip transition-colors rounded-[var(--radius-field)] bg-base-100 tune-border border-base-300 focus-within:border-primary focus-within:ring-1 focus-within:ring-primary h-[var(--h-field-md)]">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b79b23b9" class="flex-1 min-w-0 w-full bg-transparent border-0 outline-none cursor-pointer pr-3 placeholder:text-base-content/40 text-base-content text-[length:var(--text-field-md)] file:mr-3 file:border-0 file:bg-base-200 file:text-base-content file:font-medium file:cursor-pointer hover:file:bg-base-300 transition-colors file:px-4 file:py-2" @change="onChange($event)" disabled></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b79b23b9" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul><label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Disabled (dropzone)</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-primary focus-within:border-primary focus-within:ring-1 focus-within:ring-primary px-6 py-8">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-primary hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b79b2428" class="sr-only" @change="onChange($event)" disabled></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b79b2428" class="flex flex-col gap-1.5 opacity-60 [&_*]:cursor-not-allowed [&_*]:pointer-events-none" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
on a base-200 surface
<x-file-upload appearance="dropzone" color="primary" label="Upload on a base-200 panel" multiple simulate />
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Upload on a base-200 panel</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-primary focus-within:border-primary focus-within:ring-1 focus-within:ring-primary px-6 py-8">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-primary hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b7a25eb3" class="sr-only" @change="onChange($event)" multiple></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b7a25eb3" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: true, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
browse-label / drop-hint — dropzone 文案本地化
<x-file-upload
appearance="dropzone"
color="primary"
label="証明写真"
browse-label="ファイルを選択"
drop-hint="またはここにドラッグ&ドロップ"
description="PNG / JPG — max 5MB"
accept="image/*"
/>
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">証明写真</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-primary focus-within:border-primary focus-within:ring-1 focus-within:ring-primary px-6 py-8">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-primary hover:underline">ファイルを選択</span>
<span class="text-base-content/60">またはここにドラッグ&ドロップ</span></label>
</div><label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><small class="text-[length:var(--text-field-xs)] text-base-content/60">PNG / JPG — max 5MB</small>
<input x-ref="input" type="file" id="file_6a7e9b7a58edd" class="sr-only" @change="onChange($event)" accept="image/*"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b7a58edd" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>
file-upload-change 事件 — teleport 模态框内的 Livewire 集成(仅代码)
{{-- wire:model does not work on a file input teleported to <body>
(as <x-modal> does) — listen for the bubbling file-upload-change
CustomEvent and hand the File objects to $wire.upload() instead. --}}
<x-file-upload
appearance="dropzone"
label="Photo"
accept="image/*"
x-on:file-upload-change="$wire.upload('photo', $event.detail.files[0])"
/>
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="text-base-content text-[length:var(--text-field-sm)] font-medium">Photo</span></label>
<div class="flex flex-col items-center justify-center gap-2 text-center rounded-[var(--radius-box)] tune-border border-dashed border-base-300 bg-base-100 transition-colors cursor-pointer hover:border-primary focus-within:border-primary focus-within:ring-1 focus-within:ring-primary px-6 py-8">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-10 text-base-content/40" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"></path></svg></label>
<div>
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="font-semibold text-primary hover:underline">Browse</span>
<span class="text-base-content/60">or drag and drop here</span></label>
</div><label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><input x-ref="input" type="file" id="file_6a7e9b7a8c634" class="sr-only" @change="onChange($event)" accept="image/*" x-on:file-upload-change="$wire.upload('photo', $event.detail.files[0])"></label>
</div>
<ul class="mt-2 flex flex-col gap-1.5 empty:hidden" x-show="items.length > 0" x-cloak="">
<template x-for="(item, index) in items" :key="index">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<li class="flex flex-col gap-1.5 px-3 py-2 rounded-[var(--radius-field)] tune-border border-base-300 bg-base-100 text-base-content text-[length:var(--text-field-sm)]">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center justify-between gap-3">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="flex items-center gap-2.5 min-w-0">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="item.thumb">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><img class="size-10 shrink-0 rounded object-cover bg-base-200" :src="item.thumb" :alt="item.name"></label>
</template><label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<template x-if="!item.thumb">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="size-10 shrink-0 flex items-center justify-center rounded bg-base-200 text-base-content/40">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><svg class="size-5" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5A3.375 3.375 0 0 0 10.125 2.25H8.25m6.75 12-3-3m0 0-3 3m3-3v6m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"></path></svg></label>
</div><label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</template>
<div class="flex flex-col min-w-0">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><span class="truncate" x-text="item.name"></span>
<span class="text-[length:var(--text-field-xs)] text-base-content/50" x-text="fmt(item.size)"></span></label>
</div><label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div><label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"><button type="button" class="shrink-0 text-base-content/50 hover:text-error transition-colors cursor-pointer" @click.prevent="remove(index)" aria-label="Remove file"><svg class="size-4" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg></button></label>
</div><label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-1 w-full bg-base-300/60 rounded-full overflow-hidden">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
<div class="h-full bg-primary transition-[width] duration-300 ease-out" :class="item.complete ? 'bg-success!' : ''" :style="`width: ${item.progress}%`">
<label for="file_6a7e9b7a8c634" class="flex flex-col gap-1.5" x-data="{ items: [], simulate: false, fmt(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / 1024 / 1024).toFixed(1) + ' MB'; }, onChange(event) { this.releaseAll(); const list = Array.from(event.target.files || []); this.items = list.map(f => { const isImage = (f.type || '').startsWith('image/'); return { name: f.name, size: f.size, type: f.type, thumb: isImage ? URL.createObjectURL(f) : null, progress: this.simulate ? 0 : 100, complete: !this.simulate, }; }); if (this.simulate) this.runSimulation(); event.target.dispatchEvent(new CustomEvent('file-upload-change', { detail: { files: list }, bubbles: true })); }, runSimulation() { this.items.forEach(it => { const tick = () => { if (it.progress >= 100) { it.complete = true; return; } it.progress = Math.min(100, it.progress + 8 + Math.random() * 14); setTimeout(tick, 220 + Math.random() * 280); }; setTimeout(tick, 80 + Math.random() * 200); }); }, remove(index) { const it = this.items[index]; if (it && it.thumb) URL.revokeObjectURL(it.thumb); this.items.splice(index, 1); if (this.items.length === 0 && this.$refs.input) this.$refs.input.value = ''; }, releaseAll() { for (const it of this.items) if (it.thumb) URL.revokeObjectURL(it.thumb); }, }" x-init="() => { $watch('items', () => {}); }"></label>
</div>
</div>
</li>
</ul>