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: `
{{ label }}
{{ hint }}
{{ 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]; } }