@leancodepl/image-uploader 9.6.2
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/README.md +508 -0
- package/index.d.ts +1 -0
- package/index.esm.js +651 -0
- package/package.json +51 -0
- package/src/index.d.ts +5 -0
- package/src/lib/UploadImages/Cropper.d.ts +49 -0
- package/src/lib/UploadImages/CropperEditor.d.ts +35 -0
- package/src/lib/UploadImages/File.d.ts +36 -0
- package/src/lib/UploadImages/Files.d.ts +41 -0
- package/src/lib/UploadImages/Provider.d.ts +10 -0
- package/src/lib/UploadImages/Root.d.ts +31 -0
- package/src/lib/UploadImages/Zone.d.ts +32 -0
- package/src/lib/UploadImages/index.d.ts +20 -0
- package/src/lib/_hooks/useCropper.d.ts +30 -0
- package/src/lib/_hooks/useUploadImages.d.ts +101 -0
- package/src/lib/_utils/errors.d.ts +23 -0
- package/src/lib/_utils/getImagePreviewData.d.ts +1 -0
- package/src/lib/_utils/isExactFile.d.ts +1 -0
- package/src/lib/_utils/tryUploadWithUploadParams.d.ts +24 -0
- package/src/lib/config.d.ts +8 -0
- package/src/lib/types.d.ts +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
# @leancodepl/image-uploader
|
|
2
|
+
|
|
3
|
+
React component for image uploads.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @leancodepl/image-uploader
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
yarn add @leancodepl/image-uploader
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## API
|
|
16
|
+
|
|
17
|
+
### `useUploadImages(value, accept, cropper, onError, onChange)`
|
|
18
|
+
|
|
19
|
+
Manages image upload state and provides drag-and-drop functionality. Creates a complete image upload solution with file
|
|
20
|
+
validation, drag-and-drop support, optional cropping, and duplicate detection. Returns upload state and control
|
|
21
|
+
functions.
|
|
22
|
+
|
|
23
|
+
**Parameters:**
|
|
24
|
+
|
|
25
|
+
- `value?: FileWithId[]` - Current array of uploaded files with IDs
|
|
26
|
+
- `accept?: Accept` - File types to accept (defaults to image types)
|
|
27
|
+
- `cropper?: CropperConfig` - Optional cropper configuration for image editing
|
|
28
|
+
- `onError?: (errorCode: ErrorCode) => void` - Callback for handling upload errors
|
|
29
|
+
- `onChange?: (files: FileWithId[]) => void` - Callback when file list changes
|
|
30
|
+
|
|
31
|
+
**Returns:** Upload state and control functions including dropzone props
|
|
32
|
+
|
|
33
|
+
### `tryUploadWithUploadParams(image, getUploadParams)`
|
|
34
|
+
|
|
35
|
+
Uploads an image file using provided upload parameters. Handles file upload by calling the getUploadParams function to
|
|
36
|
+
retrieve upload configuration, then performs a fetch request to upload the file. Returns early if the image is already
|
|
37
|
+
uploaded.
|
|
38
|
+
|
|
39
|
+
**Parameters:**
|
|
40
|
+
|
|
41
|
+
- `image: FileWithId | UploadedFileWithId` - Image file with ID or already uploaded image with URL
|
|
42
|
+
- `getUploadParams: (image: FileWithId) => Promise<UploadParams | null | undefined>` - Function that returns upload
|
|
43
|
+
parameters (URI, method, headers) for the image
|
|
44
|
+
|
|
45
|
+
**Returns:** Promise resolving to uploaded image with URL
|
|
46
|
+
|
|
47
|
+
**Throws:** `Error` - When upload params are not defined, image is not defined, or upload fails
|
|
48
|
+
|
|
49
|
+
### `UploadImages.Root`
|
|
50
|
+
|
|
51
|
+
Root wrapper component for image upload functionality. Provides upload context to all child UploadImages components and
|
|
52
|
+
renders a div container. Must wrap all other UploadImages components to provide shared state.
|
|
53
|
+
|
|
54
|
+
**Parameters:**
|
|
55
|
+
|
|
56
|
+
- `uploader: ReturnType<typeof useUploadImages>` - Upload state and functions from `useUploadImages` hook
|
|
57
|
+
- `props: HTMLAttributes<HTMLDivElement>` - Additional HTML div attributes
|
|
58
|
+
|
|
59
|
+
**Returns:** JSX element wrapping children with upload context
|
|
60
|
+
|
|
61
|
+
### `UploadImages.Zone`
|
|
62
|
+
|
|
63
|
+
Drag-and-drop zone component for file uploads. Creates an interactive drop zone with file input capabilities. Supports
|
|
64
|
+
both click-to-select and drag-and-drop file uploads. Provides drag state to children for visual feedback.
|
|
65
|
+
|
|
66
|
+
**Parameters:**
|
|
67
|
+
|
|
68
|
+
- `children: ((props: UploadZoneChildProps) => ReactNode) | ReactNode` - Content or render function receiving drag state
|
|
69
|
+
props
|
|
70
|
+
- `props: HTMLAttributes<HTMLDivElement>` - Additional HTML div attributes
|
|
71
|
+
|
|
72
|
+
**Returns:** JSX element with drag-and-drop upload functionality
|
|
73
|
+
|
|
74
|
+
### `UploadImages.Files`
|
|
75
|
+
|
|
76
|
+
Container component for displaying uploaded files. Renders a container for uploaded files and provides current file list
|
|
77
|
+
to children. Used to display and manage the collection of uploaded images.
|
|
78
|
+
|
|
79
|
+
**Parameters:**
|
|
80
|
+
|
|
81
|
+
- `children: ((props: UploadFilesChildProps) => ReactNode) | ReactNode` - Content or render function receiving files
|
|
82
|
+
array
|
|
83
|
+
- `props: HTMLAttributes<HTMLDivElement>` - Additional HTML div attributes
|
|
84
|
+
|
|
85
|
+
**Returns:** JSX element containing uploaded files
|
|
86
|
+
|
|
87
|
+
### `UploadImages.File`
|
|
88
|
+
|
|
89
|
+
Individual file item component with preview and removal functionality. Displays a single uploaded file with preview
|
|
90
|
+
image generation and removal capability. Automatically generates image preview data and provides remove function to
|
|
91
|
+
children.
|
|
92
|
+
|
|
93
|
+
**Parameters:**
|
|
94
|
+
|
|
95
|
+
- `children: ((props: UploadFileItemChildProps) => ReactNode) | ReactNode` - Content or render function receiving file,
|
|
96
|
+
preview, and remove function
|
|
97
|
+
- `file: FileWithId` - File object with ID to display
|
|
98
|
+
- `props: HTMLAttributes<HTMLDivElement>` - Additional HTML div attributes
|
|
99
|
+
|
|
100
|
+
**Returns:** JSX element for individual file with preview and controls
|
|
101
|
+
|
|
102
|
+
### `UploadImages.Cropper`
|
|
103
|
+
|
|
104
|
+
Image cropper component with editing controls. Provides image cropping functionality with zoom, rotation, and crop area
|
|
105
|
+
controls. Processes cropped images and integrates with the upload state management.
|
|
106
|
+
|
|
107
|
+
**Parameters:**
|
|
108
|
+
|
|
109
|
+
- `children: ((props: UploadImagesCropperEditorChildProps) => ReactNode) | ReactNode` - Content or render function
|
|
110
|
+
receiving cropper controls
|
|
111
|
+
|
|
112
|
+
**Returns:** JSX element with cropper editing interface
|
|
113
|
+
|
|
114
|
+
**Throws:** `Error` - When cropper config is not defined in context
|
|
115
|
+
|
|
116
|
+
### `UploadImages.CropperEditor`
|
|
117
|
+
|
|
118
|
+
Visual editor component for image cropping. Renders the interactive crop editor interface using `"react-easy-crop"`.
|
|
119
|
+
Provides visual feedback for crop area, zoom, and rotation adjustments.
|
|
120
|
+
|
|
121
|
+
**Parameters:**
|
|
122
|
+
|
|
123
|
+
- `style?: CSSProperties` - CSS style object, merged with default positioning styles
|
|
124
|
+
- `props: HTMLAttributes<HTMLDivElement>` - Additional HTML div attributes
|
|
125
|
+
|
|
126
|
+
**Returns:** JSX element with interactive crop editor
|
|
127
|
+
|
|
128
|
+
**Throws:** `Error` - When cropper config is not defined in context
|
|
129
|
+
|
|
130
|
+
## Render Prop Types
|
|
131
|
+
|
|
132
|
+
The following types define the props passed to render functions in various components:
|
|
133
|
+
|
|
134
|
+
### `UploadZoneChildProps`
|
|
135
|
+
|
|
136
|
+
Props passed to the render function of `UploadImages.Zone` component.
|
|
137
|
+
|
|
138
|
+
**Properties:**
|
|
139
|
+
|
|
140
|
+
- `isDragActive: boolean` - True when files are being dragged over the drop zone
|
|
141
|
+
- `isFileDialogActive: boolean` - True when the native file dialog is open
|
|
142
|
+
- `isFocused: boolean` - True when the drop zone is focused (keyboard navigation)
|
|
143
|
+
|
|
144
|
+
### `UploadFilesChildProps`
|
|
145
|
+
|
|
146
|
+
Props passed to the render function of `UploadImages.Files` component.
|
|
147
|
+
|
|
148
|
+
**Properties:**
|
|
149
|
+
|
|
150
|
+
- `files?: FileWithId[]` - Array of currently uploaded files with unique IDs
|
|
151
|
+
|
|
152
|
+
### `UploadFileItemChildProps`
|
|
153
|
+
|
|
154
|
+
Props passed to the render function of `UploadImages.File` component.
|
|
155
|
+
|
|
156
|
+
**Properties:**
|
|
157
|
+
|
|
158
|
+
- `file: FileWithId` - The file object containing the original File and unique ID
|
|
159
|
+
- `preview?: string` - Base64 data URL of the image preview (undefined while loading)
|
|
160
|
+
- `remove: () => void` - Function to remove this file from the upload list
|
|
161
|
+
|
|
162
|
+
### `UploadImagesCropperEditorChildProps`
|
|
163
|
+
|
|
164
|
+
Props passed to the render function of `UploadImages.Cropper` component.
|
|
165
|
+
|
|
166
|
+
**Properties:**
|
|
167
|
+
|
|
168
|
+
- `zoom: number` - Current zoom level (1.0 = no zoom)
|
|
169
|
+
- `rotation: number` - Current rotation angle in degrees
|
|
170
|
+
- `setZoom: (zoom: number) => void` - Function to update zoom level
|
|
171
|
+
- `setRotation: (rotation: number) => void` - Function to update rotation angle
|
|
172
|
+
- `accept: () => void` - Function to accept the current crop and add to files
|
|
173
|
+
- `close: () => void` - Function to cancel cropping and close the editor
|
|
174
|
+
|
|
175
|
+
## Usage Examples
|
|
176
|
+
|
|
177
|
+
### Basic Upload
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { useState } from "react";
|
|
181
|
+
import { UploadImages, useUploadImages, FileWithId } from "@leancodepl/image-uploader";
|
|
182
|
+
|
|
183
|
+
function BasicUpload() {
|
|
184
|
+
const [files, setFiles] = useState<FileWithId[]>([]);
|
|
185
|
+
|
|
186
|
+
const uploader = useUploadImages({
|
|
187
|
+
value: files,
|
|
188
|
+
onChange: setFiles,
|
|
189
|
+
onError: (error) => console.error("Upload error:", error),
|
|
190
|
+
accept: { "image/*": [".jpg", ".png", ".gif"] }
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<UploadImages.Root uploader={uploader}>
|
|
195
|
+
<UploadImages.Zone>
|
|
196
|
+
{({ isDragActive }) => (
|
|
197
|
+
<div>
|
|
198
|
+
{isDragActive ? "Drop files here" : "Click or drag files to upload"}
|
|
199
|
+
</div>
|
|
200
|
+
)}
|
|
201
|
+
</UploadImages.Zone>
|
|
202
|
+
|
|
203
|
+
<UploadImages.Files>
|
|
204
|
+
{({ files }) => (
|
|
205
|
+
<div>
|
|
206
|
+
{files?.map(file => (
|
|
207
|
+
<UploadImages.File key={file.id} file={file}>
|
|
208
|
+
{({ preview, remove }) => (
|
|
209
|
+
<div>
|
|
210
|
+
<img src={preview} alt="Preview" />
|
|
211
|
+
<p>{file.originalFile.name}</p>
|
|
212
|
+
<button onClick={remove}>Remove</button>
|
|
213
|
+
</div>
|
|
214
|
+
)}
|
|
215
|
+
</UploadImages.File>
|
|
216
|
+
))}
|
|
217
|
+
</div>
|
|
218
|
+
)}
|
|
219
|
+
</UploadImages.Files>
|
|
220
|
+
</UploadImages.Root>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Server Upload Integration
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
import { tryUploadWithUploadParams } from "@leancodepl/image-uploader"
|
|
229
|
+
|
|
230
|
+
async function uploadToServer(image: FileWithId) {
|
|
231
|
+
try {
|
|
232
|
+
const uploadedImage = await tryUploadWithUploadParams(image, async img => {
|
|
233
|
+
// Get upload URL from your API
|
|
234
|
+
const response = await fetch("/api/upload-url", {
|
|
235
|
+
method: "POST",
|
|
236
|
+
headers: { "Content-Type": "application/json" },
|
|
237
|
+
body: JSON.stringify({
|
|
238
|
+
fileName: img.originalFile.name,
|
|
239
|
+
fileType: img.originalFile.type,
|
|
240
|
+
}),
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
const { uploadUrl, headers } = await response.json()
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
uri: uploadUrl,
|
|
247
|
+
method: "PUT",
|
|
248
|
+
requiredHeaders: headers,
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
console.log("Upload successful:", uploadedImage.url)
|
|
253
|
+
return uploadedImage
|
|
254
|
+
} catch (error) {
|
|
255
|
+
console.error("Upload failed:", error)
|
|
256
|
+
throw error
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Error Handling
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
import { ErrorCode } from "@leancodepl/image-uploader"
|
|
265
|
+
|
|
266
|
+
function handleUploadError(errorCode: ErrorCode) {
|
|
267
|
+
switch (errorCode) {
|
|
268
|
+
case ErrorCode.FileTooLarge:
|
|
269
|
+
alert("File is too large. Please choose a smaller file.")
|
|
270
|
+
break
|
|
271
|
+
case ErrorCode.FileInvalidType:
|
|
272
|
+
alert("Invalid file type. Please upload an image file.")
|
|
273
|
+
break
|
|
274
|
+
case ErrorCode.TooManyFiles:
|
|
275
|
+
alert("Too many files selected. Please choose fewer files.")
|
|
276
|
+
break
|
|
277
|
+
default:
|
|
278
|
+
alert("An error occurred while uploading the file.")
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const uploader = useUploadImages({
|
|
283
|
+
value: files,
|
|
284
|
+
onChange: setFiles,
|
|
285
|
+
onError: handleUploadError,
|
|
286
|
+
})
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Features
|
|
290
|
+
|
|
291
|
+
- **Drag-and-Drop Support**: Built on `"react-dropzone"` for intuitive file selection
|
|
292
|
+
- **Image Cropping**: Optional cropping with zoom and rotation using `"react-easy-crop"`
|
|
293
|
+
- **File Validation**: Automatic validation with customizable error handling
|
|
294
|
+
- **Preview Generation**: Automatic image preview generation for uploaded files
|
|
295
|
+
- **Duplicate Detection**: Prevents uploading the same file multiple times
|
|
296
|
+
- **TypeScript Support**: Full TypeScript definitions included
|
|
297
|
+
- **Flexible UI**: Render prop pattern for complete UI customization
|
|
298
|
+
- **Server Integration**: Helper utilities for uploading to any backend service
|
|
299
|
+
|
|
300
|
+
## Configuration
|
|
301
|
+
|
|
302
|
+
### Cropper Configuration
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
type CropperConfig = {
|
|
306
|
+
aspect: number // Aspect ratio (e.g., 16/9, 1, 4/3)
|
|
307
|
+
maxWidth?: number // Maximum output width in pixels
|
|
308
|
+
maxHeight?: number // Maximum output height in pixels
|
|
309
|
+
withRotation?: boolean // Enable rotation controls
|
|
310
|
+
withZoom?: boolean // Enable zoom controls
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### File Accept Types
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// Accept only JPEG and PNG
|
|
318
|
+
const accept = {
|
|
319
|
+
"image/jpeg": [".jpg", ".jpeg"],
|
|
320
|
+
"image/png": [".png"],
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Accept all image types (default)
|
|
324
|
+
const accept = { "image/*": [] }
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Upload with Cropping
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { useState } from "react";
|
|
331
|
+
import { UploadImages, useUploadImages, FileWithId } from "@leancodepl/image-uploader";
|
|
332
|
+
|
|
333
|
+
function CroppableUpload() {
|
|
334
|
+
const [files, setFiles] = useState<FileWithId[]>([]);
|
|
335
|
+
|
|
336
|
+
const uploader = useUploadImages({
|
|
337
|
+
value: files,
|
|
338
|
+
onChange: setFiles,
|
|
339
|
+
cropper: {
|
|
340
|
+
aspect: 16 / 9,
|
|
341
|
+
maxWidth: 800,
|
|
342
|
+
maxHeight: 450,
|
|
343
|
+
withRotation: true,
|
|
344
|
+
withZoom: true
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<UploadImages.Root uploader={uploader}>
|
|
350
|
+
<UploadImages.Zone>
|
|
351
|
+
Drop images to crop
|
|
352
|
+
</UploadImages.Zone>
|
|
353
|
+
|
|
354
|
+
<UploadImages.Cropper>
|
|
355
|
+
{({ zoom, rotation, setZoom, setRotation, accept, close }) => (
|
|
356
|
+
<div>
|
|
357
|
+
<UploadImages.CropperEditor />
|
|
358
|
+
<div>
|
|
359
|
+
<label>
|
|
360
|
+
Zoom: <input
|
|
361
|
+
type="range"
|
|
362
|
+
min={1}
|
|
363
|
+
max={3}
|
|
364
|
+
step={0.1}
|
|
365
|
+
value={zoom}
|
|
366
|
+
onChange={(e) => setZoom(Number(e.target.value))}
|
|
367
|
+
/>
|
|
368
|
+
</label>
|
|
369
|
+
<label>
|
|
370
|
+
Rotation: <input
|
|
371
|
+
type="range"
|
|
372
|
+
min={-180}
|
|
373
|
+
max={180}
|
|
374
|
+
value={rotation}
|
|
375
|
+
onChange={(e) => setRotation(Number(e.target.value))}
|
|
376
|
+
/>
|
|
377
|
+
</label>
|
|
378
|
+
<div>
|
|
379
|
+
<button onClick={accept}>Accept</button>
|
|
380
|
+
<button onClick={close}>Cancel</button>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
</div>
|
|
384
|
+
)}
|
|
385
|
+
</UploadImages.Cropper>
|
|
386
|
+
|
|
387
|
+
<UploadImages.Files>
|
|
388
|
+
{({ files }) => (
|
|
389
|
+
<div>
|
|
390
|
+
{files?.map(file => (
|
|
391
|
+
<UploadImages.File key={file.id} file={file}>
|
|
392
|
+
{({ preview, remove }) => (
|
|
393
|
+
<div>
|
|
394
|
+
<img src={preview} alt="Cropped" />
|
|
395
|
+
<button onClick={remove}>Remove</button>
|
|
396
|
+
</div>
|
|
397
|
+
)}
|
|
398
|
+
</UploadImages.File>
|
|
399
|
+
))}
|
|
400
|
+
</div>
|
|
401
|
+
)}
|
|
402
|
+
</UploadImages.Files>
|
|
403
|
+
</UploadImages.Root>
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Server Upload Integration
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
import { tryUploadWithUploadParams } from "@leancodepl/image-uploader"
|
|
412
|
+
|
|
413
|
+
async function uploadToServer(image: FileWithId) {
|
|
414
|
+
try {
|
|
415
|
+
const uploadedImage = await tryUploadWithUploadParams(image, async img => {
|
|
416
|
+
// Get upload URL from your API
|
|
417
|
+
const response = await fetch("/api/upload-url", {
|
|
418
|
+
method: "POST",
|
|
419
|
+
headers: { "Content-Type": "application/json" },
|
|
420
|
+
body: JSON.stringify({
|
|
421
|
+
fileName: img.originalFile.name,
|
|
422
|
+
fileType: img.originalFile.type,
|
|
423
|
+
}),
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
const { uploadUrl, headers } = await response.json()
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
uri: uploadUrl,
|
|
430
|
+
method: "PUT",
|
|
431
|
+
requiredHeaders: headers,
|
|
432
|
+
}
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
console.log("Upload successful:", uploadedImage.url)
|
|
436
|
+
return uploadedImage
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.error("Upload failed:", error)
|
|
439
|
+
throw error
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Error Handling
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
import { ErrorCode } from "@leancodepl/image-uploader"
|
|
448
|
+
|
|
449
|
+
function handleUploadError(errorCode: ErrorCode) {
|
|
450
|
+
switch (errorCode) {
|
|
451
|
+
case ErrorCode.FileTooLarge:
|
|
452
|
+
alert("File is too large. Please choose a smaller file.")
|
|
453
|
+
break
|
|
454
|
+
case ErrorCode.FileInvalidType:
|
|
455
|
+
alert("Invalid file type. Please upload an image file.")
|
|
456
|
+
break
|
|
457
|
+
case ErrorCode.TooManyFiles:
|
|
458
|
+
alert("Too many files selected. Please choose fewer files.")
|
|
459
|
+
break
|
|
460
|
+
default:
|
|
461
|
+
alert("An error occurred while uploading the file.")
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const uploader = useUploadImages({
|
|
466
|
+
value: files,
|
|
467
|
+
onChange: setFiles,
|
|
468
|
+
onError: handleUploadError,
|
|
469
|
+
})
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
## Features
|
|
473
|
+
|
|
474
|
+
- **Drag-and-Drop Support**: Built on `"react-dropzone"` for intuitive file selection
|
|
475
|
+
- **Image Cropping**: Optional cropping with zoom and rotation using `"react-easy-crop"`
|
|
476
|
+
- **File Validation**: Automatic validation with customizable error handling
|
|
477
|
+
- **Preview Generation**: Automatic image preview generation for uploaded files
|
|
478
|
+
- **Duplicate Detection**: Prevents uploading the same file multiple times
|
|
479
|
+
- **TypeScript Support**: Full TypeScript definitions included
|
|
480
|
+
- **Flexible UI**: Render prop pattern for complete UI customization
|
|
481
|
+
- **Server Integration**: Helper utilities for uploading to any backend service
|
|
482
|
+
|
|
483
|
+
## Configuration
|
|
484
|
+
|
|
485
|
+
### Cropper Configuration
|
|
486
|
+
|
|
487
|
+
```typescript
|
|
488
|
+
type CropperConfig = {
|
|
489
|
+
aspect: number // Aspect ratio (e.g., 16/9, 1, 4/3)
|
|
490
|
+
maxWidth?: number // Maximum output width in pixels
|
|
491
|
+
maxHeight?: number // Maximum output height in pixels
|
|
492
|
+
withRotation?: boolean // Enable rotation controls
|
|
493
|
+
withZoom?: boolean // Enable zoom controls
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### File Accept Types
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
// Accept only JPEG and PNG
|
|
501
|
+
const accept = {
|
|
502
|
+
"image/jpeg": [".jpg", ".jpeg"],
|
|
503
|
+
"image/png": [".png"],
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Accept all image types (default)
|
|
507
|
+
const accept = { "image/*": [] }
|
|
508
|
+
```
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/index";
|