Package Exports
- @alekpr/react-image-crop-uploader
- @alekpr/react-image-crop-uploader/dist/react-image-crop-uploader.css
- @alekpr/react-image-crop-uploader/style.css
Readme
React Image Crop Uploader
A comprehensive React image upload component with modal-based cropping capabilities. This library provides an all-in-one solution for handling image uploads with cropping functionality in your React applications.
Features
- ๐ Multi-file Support: Upload single or multiple images
- ๐ Image Cropping: Modal-based cropping with real-time preview using react-easy-crop
- ๐ฏ Configurable Crop: Custom aspect ratios and dimensions
- ๐ค Upload Modes: Direct upload or form integration
- ๐ผ๏ธ Image Preview: Thumbnail previews with edit functionality
- โ๏ธ Re-cropping: Edit existing images after upload
- ๐จ Customizable UI: Fully styled with standard CSS
- ๐ฑ Responsive: Mobile-friendly design
- ๐ง TypeScript: Full TypeScript support with type definitions
- ๐งช Tested: Comprehensive test suite
Installation
npm install @alekpr/react-image-crop-uploaderor
yarn add @alekpr/react-image-crop-uploaderQuick Start
import { ImageUploader } from '@alekpr/react-image-crop-uploader';
import '@alekpr/react-image-crop-uploader/style.css';
function App() {
return (
<ImageUploader
onFilesChange={(files) => console.log(files)}
cropEnabled={true}
maxFiles={5}
/>
);
}Usage
Basic Usage
import { ImageUploader } from '@alekpr/react-image-crop-uploader';
import '@alekpr/react-image-crop-uploader/style.css';
function App() {
const handleFilesChange = (files: File[]) => {
console.log('Selected files:', files);
};
return (
<ImageUploader
maxFileSize={5}
maxFiles={3}
onFilesChange={handleFilesChange}
/>
);
}With Cropping Enabled
import { ImageUploader } from '@alekpr/react-image-crop-uploader';
import '@alekpr/react-image-crop-uploader/style.css';
function App() {
const handleFilesChange = (files: File[]) => {
console.log('Selected files:', files);
};
const handleCropComplete = (croppedFile: File, originalFile: File) => {
console.log('Cropped file:', croppedFile);
};
return (
<ImageUploader
maxFileSize={10}
maxFiles={5}
enableCrop={true}
cropAspectRatio={16/9}
onFilesChange={handleFilesChange}
onCropComplete={handleCropComplete}
/>
);
}Direct Upload Mode
import { ImageUploader } from '@alekpr/react-image-crop-uploader';
import '@alekpr/react-image-crop-uploader/style.css';
function App() {
const handleUploadComplete = (response: any) => {
console.log('Upload response:', response);
};
const handleError = (error: string) => {
console.error('Upload error:', error);
};
const handleUploadProgress = (progress: number) => {
console.log(`Upload progress: ${progress}%`);
};
return (
<ImageUploader
uploadUrl="/api/images/upload"
maxFileSize={10}
enableCrop={true}
uploadFieldName="image"
multipleFileStrategy="single-request"
uploadButtonText="Upload Image"
showUploadButton={true}
onUploadComplete={handleUploadComplete}
onError={handleError}
onUploadProgress={handleUploadProgress}
/>
);
}Multiple File Upload Strategies
import { ImageUploader } from '@alekpr/react-image-crop-uploader';
import '@alekpr/react-image-crop-uploader/style.css';
// Strategy 1: Send all files in a single request
function SingleRequestUpload() {
return (
<ImageUploader
uploadUrl="/api/images/upload-multiple"
maxFiles={5}
multipleFileStrategy="single-request"
uploadFieldName="images"
onUploadComplete={(response) => console.log('All files uploaded:', response)}
/>
);
}
// Strategy 2: Send each file in separate requests
function MultipleRequestsUpload() {
return (
<ImageUploader
uploadUrl="/api/images/upload"
maxFiles={5}
multipleFileStrategy="multiple-requests"
uploadFieldName="image"
onUploadComplete={(responses) => console.log('Upload responses:', responses)}
/>
);
}
### Edit Mode
```tsx
import { ImageUploader } from '@alekpr/react-image-crop-uploader';
import '@alekpr/react-image-crop-uploader/style.css';
function App() {
const initialImages = [
'https://example.com/image1.jpg',
'https://example.com/image2.jpg'
];
const handleFilesChange = (files: File[]) => {
console.log('Updated files:', files);
};
return (
<ImageUploader
editMode={true}
initialImages={initialImages}
enableCrop={true}
showEditButton={true}
onFilesChange={handleFilesChange}
/>
);
}Props
Upload Configuration
| Prop | Type | Default | Description |
|---|---|---|---|
uploadUrl |
string |
undefined |
URL to upload files to |
maxFileSize |
number |
5 |
Maximum file size in MB |
maxFiles |
number |
1 |
Maximum number of files |
acceptedTypes |
string[] |
['image/jpeg', 'image/png', 'image/webp'] |
Accepted file types |
uploadFieldName |
string |
'image' |
FormData field name for uploaded files |
multipleFileStrategy |
'single-request' | 'multiple-requests' |
'single-request' |
How to handle multiple file uploads |
Crop Configuration
| Prop | Type | Default | Description |
|---|---|---|---|
cropAspectRatio |
`number | 'free'` | 'free' |
cropSize |
{ width: number; height: number } |
undefined |
Fixed crop size |
enableCrop |
boolean |
false |
Enable cropping functionality |
cropModalTitle |
string |
'Crop Image' |
Title for crop modal |
Initial State
| Prop | Type | Default | Description |
|---|---|---|---|
initialImages |
`string[] | File[]` | [] |
editMode |
boolean |
false |
Enable edit mode |
Callbacks
| Prop | Type | Description |
|---|---|---|
onUploadComplete |
(response: any) => void |
Called when upload completes |
onFilesChange |
(files: File[]) => void |
Called when files change |
onError |
(error: string) => void |
Called when errors occur |
onCropComplete |
(croppedFile: File, originalFile: File, index?: number) => void |
Called when cropping completes |
onCropModalOpen |
(file: File, index?: number) => void |
Called when crop modal opens |
onCropModalClose |
() => void |
Called when crop modal closes |
onUploadProgress |
(progress: number) => void |
Called with upload progress (0-100) |
UI Configuration
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder |
string |
'Drag & drop images here or click to select' |
Placeholder text |
disabled |
boolean |
false |
Disable the component |
className |
string |
'' |
Custom CSS class |
showEditButton |
boolean |
true |
Show edit button on previews |
editButtonText |
string |
'Edit' |
Text for edit button |
showUploadButton |
boolean |
true |
Show upload button when files are present |
uploadButtonText |
string |
'Upload' |
Text for upload button |
uploadButtonClassName |
string |
'' |
Custom CSS class for upload button |
Modal Configuration
| Prop | Type | Default | Description |
|---|---|---|---|
cropModalProps |
object |
{} |
Configuration for crop modal |
cropModalProps.title |
string |
'Crop Image' |
Modal title |
cropModalProps.saveButtonText |
string |
'Save' |
Save button text |
cropModalProps.cancelButtonText |
string |
'Cancel' |
Cancel button text |
cropModalProps.resetButtonText |
string |
'Reset' |
Reset button text |
Styling
The component comes with default styling. You can customize the appearance by importing the CSS file and overriding styles:
import '@alekpr/react-image-crop-uploader/style.css';Or import the CSS in your own stylesheet:
@import '@alekpr/react-image-crop-uploader/style.css';You can also import the CSS file directly from the dist folder:
import '@alekpr/react-image-crop-uploader/dist/react-image-crop-uploader.css';TypeScript Support
This library is written in TypeScript and provides full type definitions. All props and callbacks are properly typed.
Browser Support
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
Dependencies
This library uses react-easy-crop for the cropping functionality, which provides a robust and feature-rich cropping experience.
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a pull request
License
MIT ยฉ alekpr
Support
If you encounter any issues or have questions, please file an issue on GitHub.