react-muntaha-uploader
Version:
A flexible, feature-rich React hook for robust file uploads with drag-and-drop, folder support, validation, progress tracking, abort, and more.
134 lines (133 loc) • 9.09 kB
TypeScript
import React from 'react';
/**
* Union type representing all supported MIME types for file uploads.
* Includes categories for images, videos, audio, documents, archives, fonts, and more.
*/
type MimeType = 'image/*' | 'image/apng' | 'image/avif' | 'image/bmp' | 'image/cgm' | 'image/dicom-rle' | 'image/emf' | 'image/fits' | 'image/g3fax' | 'image/gif' | 'image/heic' | 'image/heif' | 'image/ief' | 'image/jls' | 'image/jp2' | 'image/jpeg' | 'image/jpg' | 'image/jph' | 'image/jpm' | 'image/jpx' | 'image/ktx' | 'image/png' | 'image/prs.btif' | 'image/prs.pti' | 'image/svg+xml' | 'image/t38' | 'image/tiff' | 'image/vnd.adobe.photoshop' | 'image/vnd.airzip.accelerator.azv' | 'image/vnd.cns.inf2' | 'image/vnd.djvu' | 'image/vnd.dwg' | 'image/vnd.dxf' | 'image/vnd.fastbidsheet' | 'image/vnd.fpx' | 'image/vnd.fst' | 'image/vnd.fujixerox.edmics-mmr' | 'image/vnd.fujixerox.edmics-rlc' | 'image/vnd.ms-modi' | 'image/vnd.net-fpx' | 'image/vnd.pco.b16' | 'image/vnd.tencent.tap' | 'image/vnd.valve.source.texture' | 'image/vnd.wap.wbmp' | 'image/vnd.xiff' | 'image/webp' | 'image/wmf' | 'image/x-cmu-raster' | 'image/x-cmx' | 'image/x-freehand' | 'image/x-icon' | 'image/x-jng' | 'image/x-mrsid-image' | 'image/x-pcx' | 'image/x-pict' | 'image/x-portable-anymap' | 'image/x-portable-bitmap' | 'image/x-portable-graymap' | 'image/x-portable-pixmap' | 'image/x-rgb' | 'image/x-xbitmap' | 'image/x-xpixmap' | 'image/x-xwindowdump' | 'video/*' | 'video/3gpp' | 'video/3gpp2' | 'video/h261' | 'video/h263' | 'video/h264' | 'video/jpeg' | 'video/jpm' | 'video/mj2' | 'video/mp4' | 'video/mpeg' | 'video/ogg' | 'video/quicktime' | 'video/vnd.dece.hd' | 'video/vnd.dece.mobile' | 'video/vnd.dece.pd' | 'video/vnd.dece.sd' | 'video/vnd.dece.video' | 'video/vnd.dvb.file' | 'video/vnd.fvt' | 'video/vnd.mpegurl' | 'video/vnd.ms-playready.media.pyv' | 'video/vnd.uvvu.mp4' | 'video/vnd.vivo' | 'video/webm' | 'video/x-f4v' | 'video/x-flv' | 'video/x-m4v' | 'video/x-ms-asf' | 'video/x-ms-wm' | 'video/x-ms-wmv' | 'video/x-ms-wmx' | 'video/x-ms-wvx' | 'video/x-msvideo' | 'video/x-sgi-movie' | 'audio/*' | 'audio/aac' | 'audio/ac3' | 'audio/adpcm' | 'audio/basic' | 'audio/midi' | 'audio/mp3' | 'audio/mp4' | 'audio/mpeg' | 'audio/ogg' | 'audio/opus' | 'audio/vorbis' | 'audio/wav' | 'audio/webm' | 'audio/x-aiff' | 'audio/x-mpegurl' | 'audio/x-ms-wax' | 'audio/x-ms-wma' | 'audio/x-pn-realaudio' | 'audio/x-wav' | 'application/*' | 'application/pdf' | 'application/msword' | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' | 'application/vnd.ms-excel' | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | 'application/vnd.ms-powerpoint' | 'application/vnd.openxmlformats-officedocument.presentationml.presentation' | 'application/rtf' | 'text/plain' | 'text/csv' | 'text/html' | 'text/css' | 'text/javascript' | 'application/json' | 'application/xml' | 'application/zip' | 'application/x-7z-compressed' | 'application/x-rar-compressed' | 'application/x-tar' | 'application/x-bzip' | 'application/x-bzip2' | 'application/gzip' | 'font/*' | 'font/otf' | 'font/ttf' | 'font/woff' | 'font/woff2' | 'application/x-httpd-php' | 'application/x-java-archive' | 'application/x-python-code' | 'application/x-ruby' | 'application/x-perl' | 'application/x-sh' | 'application/typescript' | 'application/javascript' | 'application/vnd.oasis.opendocument.text' | 'application/vnd.oasis.opendocument.spreadsheet' | 'application/vnd.oasis.opendocument.presentation' | 'application/vnd.oasis.opendocument.graphics' | 'application/vnd.oasis.opendocument.chart' | 'application/vnd.oasis.opendocument.formula' | 'application/vnd.oasis.opendocument.database' | '*';
/**
* Represents the state of files based on whether multiple files are allowed.
* @template T - Boolean indicating if multiple files are allowed
*/
type FileState<T extends boolean> = T extends true ? File[] : File | null;
/**
* Represents the state of ArrayBuffer data based on whether multiple files are allowed.
* @template T - Boolean indicating if multiple files are allowed
*/
type ArrayBufferState<T extends boolean> = T extends true ? ArrayBuffer[] : ArrayBuffer | null;
/**
* Configuration options for the drop zone hook
* @template T - Boolean indicating if multiple files are allowed
*/
interface DropZoneOptions<T extends boolean> {
/** Accepted MIME types for the files */
accept?: MimeType[];
/** Minimum file size in bytes */
minSize?: number;
/** Maximum file size in bytes */
maxSize?: number;
/** Maximum number of files allowed (only applicable when multiple is true) */
maxFiles?: number;
/** Whether multiple files are allowed */
multiple?: T;
/** Whether the drop zone is disabled */
disabled?: boolean;
/** Whether to read files as ArrayBuffer */
isArrayBuffer?: boolean;
/** Callback when files are dropped/selected */
onDrop?: (files: FileState<T>) => void;
/** Callback when an error occurs */
onError?: (err: string | null) => void;
/** Enable folder upload (requires browser support) */
enableFolderUpload?: boolean;
/** Enable keyboard navigation */
enableKeyboard?: boolean;
}
/**
* The enhanced state and methods returned by the useDrop hook with abort support
* @template T - Boolean indicating if multiple files are allowed
*/
interface EnhancedDropZoneState<T extends boolean> {
/** Current error message, if any */
error: string | null;
/** Upload progress (single number or record of indices to progress) */
progress: number | Record<number, number>;
/** The current files */
files: FileState<T>;
/** ArrayBuffer representations of files (if isArrayBuffer is true) */
arrayBuffer: ArrayBufferState<T>;
/** Whether files are currently being dragged over the drop zone */
isDragActive: boolean;
/** Function to remove files (optionally by index) */
onDelete: (index?: number) => void;
/** Aborts all current upload operations */
abortUpload: () => void;
/** Current upload status */
status: 'idle' | 'reading' | 'aborted' | 'error';
/** Utility functions */
utils: {
/** Get file(s) by index or all files */
getFile: (index?: number) => FileState<T>;
/** Get ArrayBuffer(s) by index or all ArrayBuffers */
getData: (index?: number) => ArrayBufferState<T>;
/** Get progress by index or all progress */
getProgress: (index?: number) => number | Record<number, number>;
reset: () => void;
};
/** Props to spread on the root drop zone element */
getRootProps: () => {
/** Ref for the root element */
ref: React.RefObject<HTMLDivElement>;
/** Click handler */
onClick: () => void;
/** Drag enter handler */
onDragEnter: (e: React.DragEvent<HTMLDivElement>) => void;
/** Drag over handler */
onDragOver: (e: React.DragEvent<HTMLDivElement>) => void;
/** Drag leave handler */
onDragLeave: (e: React.DragEvent<HTMLDivElement>) => void;
/** Drop handler */
onDrop: (e: React.DragEvent<HTMLDivElement>) => void;
/** Data attribute indicating drag active state */
/** Data attribute indicating drag state */
'data-dragging': boolean;
/** Data attribute indicating disabled state */
'data-disabled': boolean;
/** Data attribute indicating error state */
'data-has-error': boolean;
/** Accessible label for screen readers */
'aria-label': string;
/** Indicates whether the element is disabled for assistive technologies */
'aria-disabled': boolean;
};
/** Props to spread on the hidden file input element */
getInputProps: () => {
/** Ref for the input element */
ref: React.RefObject<HTMLInputElement>;
/** Input type */
type: 'file';
/** Input style */
style: {
display: 'none';
};
/** Accepted MIME types */
accept?: string;
/** Whether multiple files are allowed */
multiple?: boolean;
/** Whether input is disabled */
disabled?: boolean;
/** Change handler */
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
/** Allows users to select an entire directory (WebKit-specific) */
webkitdirectory?: string;
/** Allows users to select an entire directory (non-standard, used in some browsers) */
directory?: string;
};
}
/**
* A custom React hook for handling file drops and uploads with validation, progress tracking, and abort support.
* @template T - A boolean type indicating whether multiple files are allowed (defaults to true)
* @param {DropZoneOptions<T>} options - Configuration options for the drop zone
* @returns {EnhancedDropZoneState<T>} An object containing state and utility functions for the drop zone
*/
declare const useMuntahaDrop: <T extends boolean = true>(options?: DropZoneOptions<T>) => EnhancedDropZoneState<T>;
export { useMuntahaDrop };