react-smart-file-uploader 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +539 -0
- package/dist/DefaultUI.d.ts +11 -0
- package/dist/DefaultUI.d.ts.map +1 -0
- package/dist/ImageCropper.d.ts +12 -0
- package/dist/ImageCropper.d.ts.map +1 -0
- package/dist/ImageUploader.d.ts +5 -0
- package/dist/ImageUploader.d.ts.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.css +1 -0
- package/dist/index.esm.js +27711 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +27729 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 React Smart Image Uploader
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITness FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# React Smart File Uploader
|
|
2
|
+
|
|
3
|
+
🚀 A powerful and customizable file uploader component for React supporting images, PDFs, Excel, and Word documents with intelligent compression, cropping, and session persistence.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✨ **Easy to use**: Simple API with sensible defaults
|
|
8
|
+
- 📄 **Multiple file types**: Images, PDFs, Excel (.xlsx, .xls), Word (.docx, .doc)
|
|
9
|
+
- 🗜️ **Smart compression**: Automatic compression for images and PDFs
|
|
10
|
+
- 🖼️ **Image cropping**: Circle and square cropping with customizable dimensions
|
|
11
|
+
- 💾 **Session persistence**: Keep uploaded files across page refreshes
|
|
12
|
+
- 🎨 **Fully customizable**: Replace the default UI with your own components
|
|
13
|
+
- 📱 **Responsive**: Works great on desktop and mobile
|
|
14
|
+
- 🔧 **TypeScript**: Full TypeScript support with comprehensive types
|
|
15
|
+
- 🌐 **Universal**: Works with any React application
|
|
16
|
+
- 📦 **Lightweight**: Minimal dependencies
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install react-smart-file-uploader
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
or
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
yarn add react-smart-file-uploader
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import React, { useState } from 'react';
|
|
34
|
+
import { ImageUploader, ProcessedImage } from 'react-smart-file-uploader';
|
|
35
|
+
|
|
36
|
+
function App() {
|
|
37
|
+
const [files, setFiles] = useState<ProcessedImage[]>([]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div>
|
|
41
|
+
<ImageUploader
|
|
42
|
+
multiple
|
|
43
|
+
onFilesChange={setFiles}
|
|
44
|
+
accept="image/*"
|
|
45
|
+
maxFiles={5}
|
|
46
|
+
maxSize={5 * 1024 * 1024} // 5MB
|
|
47
|
+
/>
|
|
48
|
+
|
|
49
|
+
<div>
|
|
50
|
+
<h3>Uploaded Files:</h3>
|
|
51
|
+
{files.map((file, index) => (
|
|
52
|
+
<div key={index}>
|
|
53
|
+
<img src={file.url} alt={file.file.name} width={100} />
|
|
54
|
+
<p>{file.file.name}</p>
|
|
55
|
+
</div>
|
|
56
|
+
))}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Supported File Types
|
|
64
|
+
|
|
65
|
+
The uploader intelligently handles different file types:
|
|
66
|
+
|
|
67
|
+
### Images
|
|
68
|
+
- **Formats**: JPG, PNG, GIF, WebP, SVG, etc.
|
|
69
|
+
- **Compression**: ✅ Automatic (configurable quality)
|
|
70
|
+
- **Cropping**: ✅ Supported (circle/square)
|
|
71
|
+
- **Preview**: ✅ Thumbnail display
|
|
72
|
+
|
|
73
|
+
### PDFs
|
|
74
|
+
- **Formats**: PDF
|
|
75
|
+
- **Compression**: ✅ Automatic optimization
|
|
76
|
+
- **Cropping**: ❌ Not applicable
|
|
77
|
+
- **Preview**: ✅ File icon display
|
|
78
|
+
|
|
79
|
+
### Excel Spreadsheets
|
|
80
|
+
- **Formats**: .xlsx, .xls
|
|
81
|
+
- **Compression**: ❌ Disabled (preserves data integrity)
|
|
82
|
+
- **Cropping**: ❌ Not applicable
|
|
83
|
+
- **Preview**: ✅ File icon display
|
|
84
|
+
|
|
85
|
+
### Word Documents
|
|
86
|
+
- **Formats**: .docx, .doc
|
|
87
|
+
- **Compression**: ❌ Disabled (preserves formatting)
|
|
88
|
+
- **Cropping**: ❌ Not applicable
|
|
89
|
+
- **Preview**: ✅ File icon display
|
|
90
|
+
|
|
91
|
+
## API Reference
|
|
92
|
+
|
|
93
|
+
### ImageUploader Props
|
|
94
|
+
|
|
95
|
+
| Prop | Type | Default | Description |
|
|
96
|
+
|------|------|---------|-------------|
|
|
97
|
+
| `multiple` | `boolean` | `false` | Allow multiple file selection |
|
|
98
|
+
| `accept` | `string` | `undefined` | File types to accept (e.g., "image/*", "application/pdf", ".xlsx,.xls,.docx,.doc") |
|
|
99
|
+
| `maxFiles` | `number` | `10` | Maximum number of files |
|
|
100
|
+
| `maxSize` | `number` | `5242880` | Maximum file size in bytes (5MB) |
|
|
101
|
+
| `disabled` | `boolean` | `false` | Disable the uploader |
|
|
102
|
+
| `compression` | `CompressionConfig \| null` | `{ quality: 0.2, maxWidth: 1920, maxHeight: 1080 }` | Compression settings for images and PDFs (pass `null` to disable) |
|
|
103
|
+
| `crop` | `CropConfig` | `undefined` | Image cropping settings |
|
|
104
|
+
| `session` | `SessionConfig` | `undefined` | Session persistence settings |
|
|
105
|
+
| `customUI` | `(props: CustomUIProps) => ReactNode` | `undefined` | Custom UI renderer |
|
|
106
|
+
| `showPreview` | `boolean` | `true` | Show file previews |
|
|
107
|
+
| `showProgress` | `boolean` | `false` | Show upload progress |
|
|
108
|
+
| `className` | `string` | `undefined` | CSS class name |
|
|
109
|
+
| `style` | `CSSProperties` | `undefined` | Inline styles |
|
|
110
|
+
| `uploadText` | `string` | `"Click to upload or drag and drop"` | Upload area text |
|
|
111
|
+
| `dragText` | `string` | `"Drop files here"` | Drag active text |
|
|
112
|
+
| `errorText` | `object` | See below | Error messages |
|
|
113
|
+
| `onFilesChange` | `(files: ProcessedImage[]) => void` | `undefined` | Files change callback |
|
|
114
|
+
| `onError` | `(error: string) => void` | `undefined` | Error callback |
|
|
115
|
+
| `onProgress` | `(progress: number) => void` | `undefined` | Progress callback |
|
|
116
|
+
| `onCrop` | `(croppedImage: ProcessedImage) => void` | `undefined` | Crop complete callback |
|
|
117
|
+
|
|
118
|
+
### CompressionConfig
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
interface CompressionConfig {
|
|
122
|
+
quality: number; // 0.1 to 1.0
|
|
123
|
+
maxWidth?: number;
|
|
124
|
+
maxHeight?: number;
|
|
125
|
+
convertSize?: number; // Convert to JPEG if larger than this size
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### CropConfig
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
interface CropConfig {
|
|
133
|
+
enabled: boolean;
|
|
134
|
+
shape: 'circle' | 'square';
|
|
135
|
+
width?: number;
|
|
136
|
+
height?: number;
|
|
137
|
+
aspect?: number; // width/height ratio
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### SessionConfig
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
interface SessionConfig {
|
|
145
|
+
enabled: boolean;
|
|
146
|
+
key?: string; // localStorage key
|
|
147
|
+
clearOnUnmount?: boolean;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Usage Examples
|
|
152
|
+
|
|
153
|
+
### Basic Image Upload
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { ImageUploader } from 'react-smart-file-uploader';
|
|
157
|
+
|
|
158
|
+
function BasicUpload() {
|
|
159
|
+
return (
|
|
160
|
+
<ImageUploader
|
|
161
|
+
accept="image/*"
|
|
162
|
+
onFilesChange={(files) => console.log('Files:', files)}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Multi-Format File Upload
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
function MultiFormatUpload() {
|
|
172
|
+
const [files, setFiles] = useState<ProcessedImage[]>([]);
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<ImageUploader
|
|
176
|
+
multiple
|
|
177
|
+
accept="image/*,.pdf,.xlsx,.xls,.docx,.doc"
|
|
178
|
+
maxFiles={10}
|
|
179
|
+
maxSize={10 * 1024 * 1024} // 10MB
|
|
180
|
+
onFilesChange={(files) => {
|
|
181
|
+
setFiles(files);
|
|
182
|
+
files.forEach(file => {
|
|
183
|
+
console.log('File type:', file.file.fileCategory);
|
|
184
|
+
console.log('Original size:', file.file.size);
|
|
185
|
+
});
|
|
186
|
+
}}
|
|
187
|
+
/>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### PDF Upload with Compression
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
function PDFUpload() {
|
|
196
|
+
return (
|
|
197
|
+
<ImageUploader
|
|
198
|
+
multiple
|
|
199
|
+
accept=".pdf"
|
|
200
|
+
compression={{
|
|
201
|
+
quality: 0.7, // PDF compression quality
|
|
202
|
+
maxWidth: 1920,
|
|
203
|
+
maxHeight: 1080,
|
|
204
|
+
}}
|
|
205
|
+
onFilesChange={(files) => {
|
|
206
|
+
files.forEach(file => {
|
|
207
|
+
console.log('PDF compressed:', file.base64);
|
|
208
|
+
});
|
|
209
|
+
}}
|
|
210
|
+
/>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Excel/Word Upload (No Compression)
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
function DocumentUpload() {
|
|
219
|
+
return (
|
|
220
|
+
<ImageUploader
|
|
221
|
+
multiple
|
|
222
|
+
accept=".xlsx,.xls,.docx,.doc"
|
|
223
|
+
// Compression is automatically disabled for Excel and Word files
|
|
224
|
+
onFilesChange={(files) => {
|
|
225
|
+
files.forEach(file => {
|
|
226
|
+
console.log('Document uploaded:', file.file.name);
|
|
227
|
+
console.log('File category:', file.file.fileCategory);
|
|
228
|
+
});
|
|
229
|
+
}}
|
|
230
|
+
/>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Multi-Format File Upload
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
function MultiFormatUpload() {
|
|
240
|
+
const [files, setFiles] = useState<ProcessedImage[]>([]);
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<ImageUploader
|
|
244
|
+
multiple
|
|
245
|
+
accept="image/*,.pdf,.xlsx,.xls,.docx,.doc"
|
|
246
|
+
maxFiles={10}
|
|
247
|
+
maxSize={10 * 1024 * 1024} // 10MB
|
|
248
|
+
onFilesChange={(files) => {
|
|
249
|
+
setFiles(files);
|
|
250
|
+
files.forEach(file => {
|
|
251
|
+
console.log('File type:', file.file.fileCategory);
|
|
252
|
+
console.log('Original size:', file.file.size);
|
|
253
|
+
});
|
|
254
|
+
}}
|
|
255
|
+
/>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### PDF Upload with Compression
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
function PDFUpload() {
|
|
264
|
+
return (
|
|
265
|
+
<ImageUploader
|
|
266
|
+
multiple
|
|
267
|
+
accept=".pdf"
|
|
268
|
+
compression={{
|
|
269
|
+
quality: 0.7, // PDF compression quality
|
|
270
|
+
maxWidth: 1920,
|
|
271
|
+
maxHeight: 1080,
|
|
272
|
+
}}
|
|
273
|
+
onFilesChange={(files) => {
|
|
274
|
+
files.forEach(file => {
|
|
275
|
+
console.log('PDF compressed:', file.base64);
|
|
276
|
+
});
|
|
277
|
+
}}
|
|
278
|
+
/>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Excel/Word Upload (No Compression)
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
function DocumentUpload() {
|
|
287
|
+
return (
|
|
288
|
+
<ImageUploader
|
|
289
|
+
multiple
|
|
290
|
+
accept=".xlsx,.xls,.docx,.doc"
|
|
291
|
+
// Compression is automatically disabled for Excel and Word files
|
|
292
|
+
onFilesChange={(files) => {
|
|
293
|
+
files.forEach(file => {
|
|
294
|
+
console.log('Document uploaded:', file.file.name);
|
|
295
|
+
console.log('File category:', file.file.fileCategory);
|
|
296
|
+
});
|
|
297
|
+
}}
|
|
298
|
+
/>
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Multiple Files with Compression
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
function MultipleUpload() {
|
|
307
|
+
return (
|
|
308
|
+
<ImageUploader
|
|
309
|
+
multiple
|
|
310
|
+
maxFiles={10}
|
|
311
|
+
compression={{
|
|
312
|
+
quality: 0.8,
|
|
313
|
+
maxWidth: 1920,
|
|
314
|
+
maxHeight: 1080,
|
|
315
|
+
}}
|
|
316
|
+
onFilesChange={(files) => {
|
|
317
|
+
files.forEach(file => {
|
|
318
|
+
console.log('Base64:', file.base64);
|
|
319
|
+
console.log('Blob:', file.blob);
|
|
320
|
+
});
|
|
321
|
+
}}
|
|
322
|
+
/>
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Disable Compression
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
function NoCompressionUpload() {
|
|
331
|
+
return (
|
|
332
|
+
<ImageUploader
|
|
333
|
+
multiple
|
|
334
|
+
compression={null} // Disable compression entirely
|
|
335
|
+
onFilesChange={(files) => {
|
|
336
|
+
// Files will be uploaded without compression
|
|
337
|
+
console.log('Original files:', files);
|
|
338
|
+
}}
|
|
339
|
+
/>
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Image Cropping
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
function CroppingUpload() {
|
|
348
|
+
return (
|
|
349
|
+
<ImageUploader
|
|
350
|
+
crop={{
|
|
351
|
+
enabled: true,
|
|
352
|
+
shape: 'circle',
|
|
353
|
+
width: 200,
|
|
354
|
+
height: 200,
|
|
355
|
+
}}
|
|
356
|
+
onCrop={(croppedImage) => {
|
|
357
|
+
console.log('Cropped image:', croppedImage);
|
|
358
|
+
}}
|
|
359
|
+
/>
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Session Persistence
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
function PersistentUpload() {
|
|
368
|
+
return (
|
|
369
|
+
<ImageUploader
|
|
370
|
+
multiple
|
|
371
|
+
session={{
|
|
372
|
+
enabled: true,
|
|
373
|
+
key: 'my-upload-session',
|
|
374
|
+
clearOnUnmount: false,
|
|
375
|
+
}}
|
|
376
|
+
onFilesChange={(files) => {
|
|
377
|
+
// Files will persist across page refreshes
|
|
378
|
+
console.log('Persistent files:', files);
|
|
379
|
+
}}
|
|
380
|
+
/>
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Custom UI
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
function CustomUIUpload() {
|
|
389
|
+
return (
|
|
390
|
+
<ImageUploader
|
|
391
|
+
customUI={({ isDragActive, openFileDialog, files, removeFile }) => (
|
|
392
|
+
<div className="my-custom-uploader">
|
|
393
|
+
<button
|
|
394
|
+
onClick={openFileDialog}
|
|
395
|
+
className={isDragActive ? 'drag-active' : ''}
|
|
396
|
+
>
|
|
397
|
+
{isDragActive ? 'Drop it!' : 'Click to Upload'}
|
|
398
|
+
</button>
|
|
399
|
+
|
|
400
|
+
<div className="file-list">
|
|
401
|
+
{files.map((file, index) => (
|
|
402
|
+
<div key={index} className="file-item">
|
|
403
|
+
<img src={file.url} alt={file.file.name} />
|
|
404
|
+
<button onClick={() => removeFile(index)}>Remove</button>
|
|
405
|
+
</div>
|
|
406
|
+
))}
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
)}
|
|
410
|
+
/>
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Using Ref for Programmatic Control
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
import { useRef } from 'react';
|
|
419
|
+
import { ImageUploader, ImageUploaderRef } from 'react-smart-file-uploader';
|
|
420
|
+
|
|
421
|
+
function RefExample() {
|
|
422
|
+
const uploaderRef = useRef<ImageUploaderRef>(null);
|
|
423
|
+
|
|
424
|
+
const handleClearAll = () => {
|
|
425
|
+
uploaderRef.current?.clearFiles();
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
const handleOpenDialog = () => {
|
|
429
|
+
uploaderRef.current?.openFileDialog();
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const handleGetFiles = () => {
|
|
433
|
+
const files = uploaderRef.current?.getFiles();
|
|
434
|
+
console.log('Current files:', files);
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
return (
|
|
438
|
+
<div>
|
|
439
|
+
<ImageUploader ref={uploaderRef} multiple />
|
|
440
|
+
|
|
441
|
+
<div>
|
|
442
|
+
<button onClick={handleOpenDialog}>Open File Dialog</button>
|
|
443
|
+
<button onClick={handleClearAll}>Clear All</button>
|
|
444
|
+
<button onClick={handleGetFiles}>Get Files</button>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Styling
|
|
452
|
+
|
|
453
|
+
The component uses Tailwind CSS classes by default, but you can easily customize the styling:
|
|
454
|
+
|
|
455
|
+
### Using CSS Classes
|
|
456
|
+
|
|
457
|
+
```tsx
|
|
458
|
+
<ImageUploader
|
|
459
|
+
className="my-uploader"
|
|
460
|
+
// ... other props
|
|
461
|
+
/>
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
```css
|
|
465
|
+
.my-uploader {
|
|
466
|
+
border: 2px dashed #ccc;
|
|
467
|
+
border-radius: 8px;
|
|
468
|
+
padding: 20px;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.my-uploader:hover {
|
|
472
|
+
border-color: #007bff;
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Using Inline Styles
|
|
477
|
+
|
|
478
|
+
```tsx
|
|
479
|
+
<ImageUploader
|
|
480
|
+
style={{
|
|
481
|
+
border: '2px dashed #ccc',
|
|
482
|
+
borderRadius: '8px',
|
|
483
|
+
padding: '20px',
|
|
484
|
+
}}
|
|
485
|
+
/>
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## TypeScript Support
|
|
489
|
+
|
|
490
|
+
The package is written in TypeScript and provides comprehensive type definitions:
|
|
491
|
+
|
|
492
|
+
```tsx
|
|
493
|
+
import {
|
|
494
|
+
ImageUploader,
|
|
495
|
+
ProcessedImage,
|
|
496
|
+
ImageUploaderProps,
|
|
497
|
+
ImageUploaderRef,
|
|
498
|
+
CropConfig,
|
|
499
|
+
CompressionConfig,
|
|
500
|
+
SessionConfig,
|
|
501
|
+
} from 'react-smart-file-uploader';
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
## Browser Support
|
|
505
|
+
|
|
506
|
+
- Chrome (latest)
|
|
507
|
+
- Firefox (latest)
|
|
508
|
+
- Safari (latest)
|
|
509
|
+
- Edge (latest)
|
|
510
|
+
|
|
511
|
+
## Contributing
|
|
512
|
+
|
|
513
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
514
|
+
|
|
515
|
+
## License
|
|
516
|
+
|
|
517
|
+
MIT © [Your Name]
|
|
518
|
+
|
|
519
|
+
## Changelog
|
|
520
|
+
|
|
521
|
+
### v2.0.0 (Latest)
|
|
522
|
+
- 🎉 **Major Update**: Multi-format file support
|
|
523
|
+
- ✨ Added support for PDF files with automatic compression
|
|
524
|
+
- ✨ Added support for Excel files (.xlsx, .xls) - compression disabled
|
|
525
|
+
- ✨ Added support for Word documents (.docx, .doc) - compression disabled
|
|
526
|
+
- 🔧 Added `fileCategory` property to track file types
|
|
527
|
+
- 🔧 Enhanced file type detection with `getFileCategory` utility
|
|
528
|
+
- 🎨 Improved file preview with type-specific icons
|
|
529
|
+
- 📝 Renamed package from `react-smart-image-uploader` to `react-smart-file-uploader`
|
|
530
|
+
- 📚 Updated documentation with multi-format examples
|
|
531
|
+
|
|
532
|
+
### v1.0.0
|
|
533
|
+
- Initial release
|
|
534
|
+
- Image upload with drag & drop
|
|
535
|
+
- Image compression
|
|
536
|
+
- Image cropping (circle/square)
|
|
537
|
+
- Session persistence
|
|
538
|
+
- Custom UI support
|
|
539
|
+
- TypeScript support
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CustomUIProps } from './types';
|
|
3
|
+
interface DefaultUIProps extends CustomUIProps {
|
|
4
|
+
uploadText?: string;
|
|
5
|
+
dragText?: string;
|
|
6
|
+
showPreview?: boolean;
|
|
7
|
+
multiple?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare const DefaultUI: React.FC<DefaultUIProps>;
|
|
10
|
+
export default DefaultUI;
|
|
11
|
+
//# sourceMappingURL=DefaultUI.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultUI.d.ts","sourceRoot":"","sources":["../src/DefaultUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAkB,MAAM,SAAS,CAAC;AAGxD,UAAU,cAAe,SAAQ,aAAa;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAyKvC,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import 'react-image-crop/dist/ReactCrop.css';
|
|
3
|
+
import { ProcessedImage, CropConfig } from './types';
|
|
4
|
+
interface ImageCropperProps {
|
|
5
|
+
image: ProcessedImage;
|
|
6
|
+
cropConfig: CropConfig;
|
|
7
|
+
onCropComplete: (croppedImage: ProcessedImage) => void;
|
|
8
|
+
onCancel: () => void;
|
|
9
|
+
}
|
|
10
|
+
declare const ImageCropper: React.FC<ImageCropperProps>;
|
|
11
|
+
export default ImageCropper;
|
|
12
|
+
//# sourceMappingURL=ImageCropper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageCropper.d.ts","sourceRoot":"","sources":["../src/ImageCropper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAO7D,OAAO,qCAAqC,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErD,UAAU,iBAAiB;IACzB,KAAK,EAAE,cAAc,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,cAAc,EAAE,CAAC,YAAY,EAAE,cAAc,KAAK,IAAI,CAAC;IACvD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmK7C,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ImageUploaderProps, ImageUploaderRef } from './types';
|
|
3
|
+
declare const ImageUploader: React.ForwardRefExoticComponent<ImageUploaderProps & React.RefAttributes<ImageUploaderRef>>;
|
|
4
|
+
export default ImageUploader;
|
|
5
|
+
//# sourceMappingURL=ImageUploader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageUploader.d.ts","sourceRoot":"","sources":["../src/ImageUploader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AACf,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAEjB,MAAM,SAAS,CAAC;AAcjB,QAAA,MAAM,aAAa,6FAyVlB,CAAC;AAIF,eAAe,aAAa,CAAC"}
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@keyframes marching-ants{0%{background-position:0 0,0 100%,0 0,100% 0}to{background-position:20px 0,-20px 100%,0 -20px,100% 20px}}:root{--rc-drag-handle-size:12px;--rc-drag-handle-mobile-size:24px;--rc-drag-handle-bg-colour:rgba(0,0,0,.2);--rc-drag-bar-size:6px;--rc-border-color:hsla(0,0%,100%,.7);--rc-focus-color:#08f}.ReactCrop{cursor:crosshair;display:inline-block;max-width:100%;position:relative}.ReactCrop *,.ReactCrop :after,.ReactCrop :before{box-sizing:border-box}.ReactCrop--disabled,.ReactCrop--locked{cursor:inherit}.ReactCrop__child-wrapper{max-height:inherit;overflow:hidden}.ReactCrop__child-wrapper>img,.ReactCrop__child-wrapper>video{display:block;max-height:inherit;max-width:100%}.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__child-wrapper>img,.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__child-wrapper>video,.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__crop-selection{touch-action:none}.ReactCrop__crop-mask{bottom:0;height:calc(100% + .5px);left:0;pointer-events:none;position:absolute;right:0;top:0;width:calc(100% + .5px)}.ReactCrop__crop-selection{cursor:move;left:0;position:absolute;top:0;transform:translateZ(0)}.ReactCrop--disabled .ReactCrop__crop-selection{cursor:inherit}.ReactCrop--circular-crop .ReactCrop__crop-selection{border-radius:50%}.ReactCrop--circular-crop .ReactCrop__crop-selection:after{border:1px solid var(--rc-border-color);bottom:-1px;content:"";left:-1px;opacity:.3;pointer-events:none;position:absolute;right:-1px;top:-1px}.ReactCrop--no-animate .ReactCrop__crop-selection{outline:1px dashed #fff}.ReactCrop__crop-selection:not(.ReactCrop--no-animate .ReactCrop__crop-selection){animation:marching-ants 1s;animation-iteration-count:infinite;animation-play-state:running;animation-timing-function:linear;background-image:linear-gradient(90deg,#fff 50%,#444 0),linear-gradient(90deg,#fff 50%,#444 0),linear-gradient(180deg,#fff 50%,#444 0),linear-gradient(180deg,#fff 50%,#444 0);background-position:0 0,0 100%,0 0,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:10px 1px,10px 1px,1px 10px,1px 10px;color:#fff}.ReactCrop__crop-selection:focus{outline:2px solid var(--rc-focus-color);outline-offset:-1px}.ReactCrop--invisible-crop .ReactCrop__crop-mask,.ReactCrop--invisible-crop .ReactCrop__crop-selection{display:none}.ReactCrop__rule-of-thirds-hz:after,.ReactCrop__rule-of-thirds-hz:before,.ReactCrop__rule-of-thirds-vt:after,.ReactCrop__rule-of-thirds-vt:before{background-color:#fff6;content:"";display:block;position:absolute}.ReactCrop__rule-of-thirds-vt:after,.ReactCrop__rule-of-thirds-vt:before{height:100%;width:1px}.ReactCrop__rule-of-thirds-vt:before{left:33.3333333333%}.ReactCrop__rule-of-thirds-vt:after{left:66.6666666667%}.ReactCrop__rule-of-thirds-hz:after,.ReactCrop__rule-of-thirds-hz:before{height:1px;width:100%}.ReactCrop__rule-of-thirds-hz:before{top:33.3333333333%}.ReactCrop__rule-of-thirds-hz:after{top:66.6666666667%}.ReactCrop__drag-handle{background-color:var(--rc-drag-handle-bg-colour);border:1px solid var(--rc-border-color);height:var(--rc-drag-handle-size);position:absolute;width:var(--rc-drag-handle-size)}.ReactCrop__drag-handle:focus{background:var(--rc-focus-color)}.ReactCrop .ord-nw{cursor:nw-resize;left:0;top:0;transform:translate(-50%,-50%)}.ReactCrop .ord-n{cursor:n-resize;left:50%;top:0;transform:translate(-50%,-50%)}.ReactCrop .ord-ne{cursor:ne-resize;top:0}.ReactCrop .ord-e,.ReactCrop .ord-ne{right:0;transform:translate(50%,-50%)}.ReactCrop .ord-e{cursor:e-resize;top:50%}.ReactCrop .ord-se{bottom:0;cursor:se-resize;right:0;transform:translate(50%,50%)}.ReactCrop .ord-s{cursor:s-resize;left:50%}.ReactCrop .ord-s,.ReactCrop .ord-sw{bottom:0;transform:translate(-50%,50%)}.ReactCrop .ord-sw{cursor:sw-resize;left:0}.ReactCrop .ord-w{cursor:w-resize;left:0;top:50%;transform:translate(-50%,-50%)}.ReactCrop__disabled .ReactCrop__drag-handle{cursor:inherit}.ReactCrop__drag-bar{position:absolute}.ReactCrop__drag-bar.ord-n{height:var(--rc-drag-bar-size);left:0;top:0;transform:translateY(-50%);width:100%}.ReactCrop__drag-bar.ord-e{height:100%;right:0;top:0;transform:translate(50%);width:var(--rc-drag-bar-size)}.ReactCrop__drag-bar.ord-s{bottom:0;height:var(--rc-drag-bar-size);left:0;transform:translateY(50%);width:100%}.ReactCrop__drag-bar.ord-w{height:100%;left:0;top:0;transform:translate(-50%);width:var(--rc-drag-bar-size)}.ReactCrop--fixed-aspect .ReactCrop__drag-bar,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-e,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-n,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-s,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-w,.ReactCrop--new-crop .ReactCrop__drag-bar,.ReactCrop--new-crop .ReactCrop__drag-handle{display:none}@media (pointer:coarse){.ReactCrop .ord-e,.ReactCrop .ord-n,.ReactCrop .ord-s,.ReactCrop .ord-w{display:none}.ReactCrop__drag-handle{height:var(--rc-drag-handle-mobile-size);width:var(--rc-drag-handle-mobile-size)}}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as ImageUploader } from './ImageUploader';
|
|
2
|
+
export { default as DefaultUI } from './DefaultUI';
|
|
3
|
+
export { default as ImageCropper } from './ImageCropper';
|
|
4
|
+
export type { ImageFile, ProcessedImage, CropConfig, CompressionConfig, SessionConfig, CustomUIProps, ImageUploaderProps, ImageUploaderRef, } from './types';
|
|
5
|
+
export { validateFileSize, validateFileType, fileToBase64, compressImage, processFile, saveToSession, loadFromSession, clearSession, parseAcceptProp, formatFileSize, cleanupUrls, } from './utils';
|
|
6
|
+
export { default } from './ImageUploader';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGzD,YAAY,EACV,SAAS,EACT,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,aAAa,EACb,eAAe,EACf,YAAY,EACZ,eAAe,EACf,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@keyframes marching-ants{0%{background-position:0 0,0 100%,0 0,100% 0}to{background-position:20px 0,-20px 100%,0 -20px,100% 20px}}:root{--rc-drag-handle-size:12px;--rc-drag-handle-mobile-size:24px;--rc-drag-handle-bg-colour:rgba(0,0,0,.2);--rc-drag-bar-size:6px;--rc-border-color:hsla(0,0%,100%,.7);--rc-focus-color:#08f}.ReactCrop{cursor:crosshair;display:inline-block;max-width:100%;position:relative}.ReactCrop *,.ReactCrop :after,.ReactCrop :before{box-sizing:border-box}.ReactCrop--disabled,.ReactCrop--locked{cursor:inherit}.ReactCrop__child-wrapper{max-height:inherit;overflow:hidden}.ReactCrop__child-wrapper>img,.ReactCrop__child-wrapper>video{display:block;max-height:inherit;max-width:100%}.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__child-wrapper>img,.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__child-wrapper>video,.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__crop-selection{touch-action:none}.ReactCrop__crop-mask{bottom:0;height:calc(100% + .5px);left:0;pointer-events:none;position:absolute;right:0;top:0;width:calc(100% + .5px)}.ReactCrop__crop-selection{cursor:move;left:0;position:absolute;top:0;transform:translateZ(0)}.ReactCrop--disabled .ReactCrop__crop-selection{cursor:inherit}.ReactCrop--circular-crop .ReactCrop__crop-selection{border-radius:50%}.ReactCrop--circular-crop .ReactCrop__crop-selection:after{border:1px solid var(--rc-border-color);bottom:-1px;content:"";left:-1px;opacity:.3;pointer-events:none;position:absolute;right:-1px;top:-1px}.ReactCrop--no-animate .ReactCrop__crop-selection{outline:1px dashed #fff}.ReactCrop__crop-selection:not(.ReactCrop--no-animate .ReactCrop__crop-selection){animation:marching-ants 1s;animation-iteration-count:infinite;animation-play-state:running;animation-timing-function:linear;background-image:linear-gradient(90deg,#fff 50%,#444 0),linear-gradient(90deg,#fff 50%,#444 0),linear-gradient(180deg,#fff 50%,#444 0),linear-gradient(180deg,#fff 50%,#444 0);background-position:0 0,0 100%,0 0,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:10px 1px,10px 1px,1px 10px,1px 10px;color:#fff}.ReactCrop__crop-selection:focus{outline:2px solid var(--rc-focus-color);outline-offset:-1px}.ReactCrop--invisible-crop .ReactCrop__crop-mask,.ReactCrop--invisible-crop .ReactCrop__crop-selection{display:none}.ReactCrop__rule-of-thirds-hz:after,.ReactCrop__rule-of-thirds-hz:before,.ReactCrop__rule-of-thirds-vt:after,.ReactCrop__rule-of-thirds-vt:before{background-color:#fff6;content:"";display:block;position:absolute}.ReactCrop__rule-of-thirds-vt:after,.ReactCrop__rule-of-thirds-vt:before{height:100%;width:1px}.ReactCrop__rule-of-thirds-vt:before{left:33.3333333333%}.ReactCrop__rule-of-thirds-vt:after{left:66.6666666667%}.ReactCrop__rule-of-thirds-hz:after,.ReactCrop__rule-of-thirds-hz:before{height:1px;width:100%}.ReactCrop__rule-of-thirds-hz:before{top:33.3333333333%}.ReactCrop__rule-of-thirds-hz:after{top:66.6666666667%}.ReactCrop__drag-handle{background-color:var(--rc-drag-handle-bg-colour);border:1px solid var(--rc-border-color);height:var(--rc-drag-handle-size);position:absolute;width:var(--rc-drag-handle-size)}.ReactCrop__drag-handle:focus{background:var(--rc-focus-color)}.ReactCrop .ord-nw{cursor:nw-resize;left:0;top:0;transform:translate(-50%,-50%)}.ReactCrop .ord-n{cursor:n-resize;left:50%;top:0;transform:translate(-50%,-50%)}.ReactCrop .ord-ne{cursor:ne-resize;top:0}.ReactCrop .ord-e,.ReactCrop .ord-ne{right:0;transform:translate(50%,-50%)}.ReactCrop .ord-e{cursor:e-resize;top:50%}.ReactCrop .ord-se{bottom:0;cursor:se-resize;right:0;transform:translate(50%,50%)}.ReactCrop .ord-s{cursor:s-resize;left:50%}.ReactCrop .ord-s,.ReactCrop .ord-sw{bottom:0;transform:translate(-50%,50%)}.ReactCrop .ord-sw{cursor:sw-resize;left:0}.ReactCrop .ord-w{cursor:w-resize;left:0;top:50%;transform:translate(-50%,-50%)}.ReactCrop__disabled .ReactCrop__drag-handle{cursor:inherit}.ReactCrop__drag-bar{position:absolute}.ReactCrop__drag-bar.ord-n{height:var(--rc-drag-bar-size);left:0;top:0;transform:translateY(-50%);width:100%}.ReactCrop__drag-bar.ord-e{height:100%;right:0;top:0;transform:translate(50%);width:var(--rc-drag-bar-size)}.ReactCrop__drag-bar.ord-s{bottom:0;height:var(--rc-drag-bar-size);left:0;transform:translateY(50%);width:100%}.ReactCrop__drag-bar.ord-w{height:100%;left:0;top:0;transform:translate(-50%);width:var(--rc-drag-bar-size)}.ReactCrop--fixed-aspect .ReactCrop__drag-bar,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-e,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-n,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-s,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-w,.ReactCrop--new-crop .ReactCrop__drag-bar,.ReactCrop--new-crop .ReactCrop__drag-handle{display:none}@media (pointer:coarse){.ReactCrop .ord-e,.ReactCrop .ord-n,.ReactCrop .ord-s,.ReactCrop .ord-w{display:none}.ReactCrop__drag-handle{height:var(--rc-drag-handle-mobile-size);width:var(--rc-drag-handle-mobile-size)}}
|