import {
Component,
Input,
Output,
EventEmitter,
ChangeDetectionStrategy,
ChangeDetectorRef,
ElementRef,
ViewChild,
inject,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import 'mayvio-ui/fileupload/css';
@Component({
selector: 'mv-fileupload',
standalone: true,
imports: [CommonModule],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
0">
{{ file.name }}
{{ formatSize(file.size) }}
`,
})
export class FileUploadComponent {
@Input() multiple = false;
@Input() accept?: string;
@Input() maxSize?: number;
@Input() disabled = false;
@Input() label = 'Drag and drop files here or click to browse';
@Input() hint = 'Max file size: 5MB';
@Input() className = '';
@Output() fileChange = new EventEmitter();
@ViewChild('fileInput') fileInputRef!: ElementRef;
files: File[] = [];
isDragActive = false;
private cdr = inject(ChangeDetectorRef);
onDragOver(e: DragEvent) {
e.preventDefault();
if (!this.disabled) {
this.isDragActive = true;
this.cdr.markForCheck();
}
}
onDragLeave(e: DragEvent) {
e.preventDefault();
this.isDragActive = false;
this.cdr.markForCheck();
}
onDrop(e: DragEvent) {
e.preventDefault();
this.isDragActive = false;
if (this.disabled) return;
if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {
this.handleFiles(e.dataTransfer.files);
}
this.cdr.markForCheck();
}
onFileInputChange(e: Event) {
const target = e.target as HTMLInputElement;
if (target.files && target.files.length > 0) {
this.handleFiles(target.files);
}
if (this.fileInputRef?.nativeElement) {
this.fileInputRef.nativeElement.value = '';
}
}
handleFiles(fileList: FileList) {
let validFiles = Array.from(fileList);
if (this.maxSize) {
validFiles = validFiles.filter((f) => f.size <= this.maxSize!);
}
if (!this.multiple && validFiles.length > 0) {
validFiles = [validFiles[0]];
}
this.files = this.multiple ? [...this.files, ...validFiles] : validFiles;
this.fileChange.emit(this.files);
this.cdr.markForCheck();
}
removeFile(index: number) {
this.files.splice(index, 1);
this.files = [...this.files];
this.fileChange.emit(this.files);
this.cdr.markForCheck();
}
formatSize(bytes: number): string {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
}