its-just-ui
Version:
ITS Just UI - The easiest and best React UI component library. Modern, accessible, and customizable components built with TypeScript and Tailwind CSS. Simple to use, production-ready components for building beautiful user interfaces with ease.
215 lines (213 loc) • 7.36 kB
TypeScript
import { default as React, ReactNode, HTMLAttributes, ButtonHTMLAttributes, CSSProperties } from 'react';
/**
* Upload is a comprehensive file upload component with drag-and-drop support, progress tracking, and compound component architecture.
*
* ## Features
* - **Controlled Component**: Parent manages file state through `files` and `onChange` props
* - **Compound Components**: Modular architecture with Dropzone, Preview, Progress, FileList, and Button sub-components
* - **Drag & Drop**: Full support for drag-and-drop file uploads with visual feedback
* - **File Validation**: Built-in max file size and count restrictions
* - **Progress Tracking**: Visual progress indicators for file uploads
* - **Multiple Variants**: 5 pre-defined visual styles (default, bordered, dashed, card, ghost)
* - **3 Sizes**: Small, medium, and large options
* - **Status States**: Built-in support for success, warning, and error states
* - **Extensive Styling**: Over 30 style props for complete customization
* - **Custom Rendering**: Support for custom file items, dropzone, and progress rendering
* - **Accessibility**: Full keyboard navigation and ARIA support
* - **Form Ready**: Works seamlessly in forms with required field support
*
* ## Usage
*
* ### Basic Usage (Controlled):
* ```tsx
* const [files, setFiles] = useState<File[]>([])
*
* <Upload
* files={files}
* onChange={setFiles}
* accept="image/*"
* multiple
* />
* ```
*
* ### With Restrictions:
* ```tsx
* <Upload
* files={files}
* onChange={setFiles}
* maxFiles={5}
* maxSize={5 * 1024 * 1024} // 5MB
* accept=".pdf,.doc,.docx"
* helperText="PDF or Word documents only. Max 5 files, 5MB each."
* />
* ```
*
* ### Using Compound Components:
* ```tsx
* <Upload files={files} onChange={setFiles}>
* <Upload.Dropzone className="custom-dropzone">
* <MyCustomDropzoneContent />
* </Upload.Dropzone>
* <Upload.FileList>
* <Upload.Button>Select Files</Upload.Button>
* </Upload.FileList>
* </Upload>
* ```
*
* ### With Custom File Preview:
* ```tsx
* <Upload
* files={files}
* onChange={setFiles}
* renderFileItem={(file, index) => (
* <div className="custom-file-item">
* <Upload.Preview file={file} />
* <span>{file.file.name}</span>
* <Upload.Progress file={file} />
* </div>
* )}
* />
* ```
*
* ### Form Integration:
* ```tsx
* <form onSubmit={handleSubmit}>
* <Upload
* files={files}
* onChange={setFiles}
* label="Upload Documents"
* required
* helperText="Please upload supporting documents"
* />
* <button type="submit">Submit</button>
* </form>
* ```
*
* @example
* ```tsx
* // Simple image upload
* <Upload
* files={files}
* onChange={setFiles}
* accept="image/*"
* variant="dashed"
* size="lg"
* />
*
* // Async upload with progress
* <Upload
* files={files}
* onChange={setFiles}
* onUploadStart={(file) => console.log('Starting upload:', file.name)}
* onUploadProgress={(file, progress) => console.log(`${file.name}: ${progress}%`)}
* onUploadComplete={(file) => console.log('Completed:', file.name)}
* />
* ```
*/
export interface FileWithProgress {
id: string;
file: File;
progress?: number;
status?: 'pending' | 'uploading' | 'success' | 'error';
error?: string;
}
export type UploadVariant = 'default' | 'bordered' | 'dashed' | 'card' | 'ghost';
export type UploadSize = 'sm' | 'md' | 'lg';
export type UploadStatus = 'default' | 'success' | 'warning' | 'error';
export interface UploadStyleProps {
borderWidth?: string | number;
borderColor?: string;
borderStyle?: string;
borderRadius?: string | number;
fontSize?: string | number;
fontWeight?: string | number;
fontFamily?: string;
textColor?: string;
placeholderColor?: string;
backgroundColor?: string;
hoverBackgroundColor?: string;
activeColor?: string;
focusRingColor?: string;
focusRingWidth?: string | number;
focusRingOffset?: string | number;
focusBorderColor?: string;
focusBackgroundColor?: string;
boxShadow?: string;
focusBoxShadow?: string;
padding?: string | number;
paddingX?: string | number;
paddingY?: string | number;
margin?: string | number;
gap?: string | number;
uploadIconColor?: string;
deleteIconColor?: string;
successIconColor?: string;
errorIconColor?: string;
transitionDuration?: string | number;
}
export interface UploadProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'onError' | 'onDrop'>, UploadStyleProps {
files?: File[];
onChange?: (files: File[]) => void;
accept?: string;
multiple?: boolean;
maxFiles?: number;
maxSize?: number;
disabled?: boolean;
required?: boolean;
loading?: boolean;
variant?: UploadVariant;
size?: UploadSize;
status?: UploadStatus;
label?: ReactNode;
helperText?: ReactNode;
emptyStateMessage?: ReactNode;
onDrop?: (files: File[]) => void;
onUploadStart?: (file: File) => void;
onUploadProgress?: (file: File, progress: number) => void;
onUploadComplete?: (file: File) => void;
onRemoveFile?: (file: File) => void;
onError?: (error: Error, file?: File) => void;
renderFileItem?: (file: FileWithProgress, index: number) => ReactNode;
renderDropzone?: (isDragging: boolean) => ReactNode;
renderProgress?: (file: FileWithProgress) => ReactNode;
dropzoneStyle?: CSSProperties;
fileListStyle?: CSSProperties;
buttonStyle?: CSSProperties;
progressStyle?: CSSProperties;
previewStyle?: CSSProperties;
}
interface UploadContextValue {
files: FileWithProgress[];
setFiles: (files: FileWithProgress[]) => void;
addFiles: (newFiles: File[]) => void;
removeFile: (fileId: string) => void;
updateFileProgress: (fileId: string, progress: number) => void;
updateFileStatus: (fileId: string, status: FileWithProgress['status'], error?: string) => void;
props: UploadProps;
isDragging: boolean;
setIsDragging: (isDragging: boolean) => void;
}
export declare const useUploadContext: () => UploadContextValue;
export interface DropzoneProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
}
export interface UploadProgressProps extends HTMLAttributes<HTMLDivElement> {
file: FileWithProgress;
}
export interface PreviewProps extends HTMLAttributes<HTMLDivElement> {
file: FileWithProgress;
}
export interface FileListProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
}
export interface UploadButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children?: ReactNode;
}
export declare const Upload: React.ForwardRefExoticComponent<UploadProps & React.RefAttributes<HTMLDivElement>> & {
Dropzone: React.ForwardRefExoticComponent<DropzoneProps & React.RefAttributes<HTMLDivElement>>;
Preview: React.ForwardRefExoticComponent<PreviewProps & React.RefAttributes<HTMLDivElement>>;
Progress: React.ForwardRefExoticComponent<UploadProgressProps & React.RefAttributes<HTMLDivElement>>;
FileList: React.ForwardRefExoticComponent<FileListProps & React.RefAttributes<HTMLDivElement>>;
Button: React.ForwardRefExoticComponent<UploadButtonProps & React.RefAttributes<HTMLButtonElement>>;
};
export {};