@leancodepl/image-uploader 9.7.2 → 9.7.4

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/LICENSE +201 -0
  3. package/dist/index.d.ts +6 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +3903 -0
  6. package/dist/index.umd.cjs +86 -0
  7. package/{src → dist}/lib/UploadImages/Cropper.d.ts +3 -2
  8. package/dist/lib/UploadImages/Cropper.d.ts.map +1 -0
  9. package/{src → dist}/lib/UploadImages/CropperEditor.d.ts +2 -1
  10. package/dist/lib/UploadImages/CropperEditor.d.ts.map +1 -0
  11. package/{src → dist}/lib/UploadImages/File.d.ts +3 -2
  12. package/dist/lib/UploadImages/File.d.ts.map +1 -0
  13. package/{src → dist}/lib/UploadImages/Files.d.ts +3 -2
  14. package/dist/lib/UploadImages/Files.d.ts.map +1 -0
  15. package/{src → dist}/lib/UploadImages/Provider.d.ts +3 -2
  16. package/dist/lib/UploadImages/Provider.d.ts.map +1 -0
  17. package/{src → dist}/lib/UploadImages/Root.d.ts +3 -2
  18. package/dist/lib/UploadImages/Root.d.ts.map +1 -0
  19. package/{src → dist}/lib/UploadImages/Zone.d.ts +3 -2
  20. package/dist/lib/UploadImages/Zone.d.ts.map +1 -0
  21. package/dist/lib/UploadImages/index.d.ts +21 -0
  22. package/dist/lib/UploadImages/index.d.ts.map +1 -0
  23. package/{src → dist}/lib/_hooks/useCropper.d.ts +9 -8
  24. package/dist/lib/_hooks/useCropper.d.ts.map +1 -0
  25. package/{src → dist}/lib/_hooks/useUploadImages.d.ts +19 -18
  26. package/dist/lib/_hooks/useUploadImages.d.ts.map +1 -0
  27. package/{src → dist}/lib/_utils/errors.d.ts +2 -1
  28. package/dist/lib/_utils/errors.d.ts.map +1 -0
  29. package/{src → dist}/lib/_utils/getImagePreviewData.d.ts +1 -0
  30. package/dist/lib/_utils/getImagePreviewData.d.ts.map +1 -0
  31. package/{src → dist}/lib/_utils/isExactFile.d.ts +1 -0
  32. package/dist/lib/_utils/isExactFile.d.ts.map +1 -0
  33. package/{src → dist}/lib/_utils/tryUploadWithUploadParams.d.ts +2 -1
  34. package/dist/lib/_utils/tryUploadWithUploadParams.d.ts.map +1 -0
  35. package/{src → dist}/lib/config.d.ts +2 -1
  36. package/dist/lib/config.d.ts.map +1 -0
  37. package/{src → dist}/lib/types.d.ts +2 -1
  38. package/dist/lib/types.d.ts.map +1 -0
  39. package/package.json +20 -6
  40. package/index.d.ts +0 -1
  41. package/index.esm.js +0 -651
  42. package/src/index.d.ts +0 -5
  43. package/src/lib/UploadImages/index.d.ts +0 -20
package/index.esm.js DELETED
@@ -1,651 +0,0 @@
1
- import { ErrorCode as ErrorCode$1, useDropzone } from 'react-dropzone';
2
- import { useContext, createContext, useCallback, useState, useEffect } from 'react';
3
- import { jsx, jsxs } from 'react/jsx-runtime';
4
- import EasyCrop from 'react-easy-crop';
5
- import { v4 } from 'uuid';
6
- import { useSyncState } from '@leancodepl/utils';
7
-
8
- var ErrorCode;
9
- (function(ErrorCode) {
10
- ErrorCode[ErrorCode["FileTooLarge"] = ErrorCode$1.FileTooLarge] = "FileTooLarge";
11
- ErrorCode[ErrorCode["FileTooSmall"] = ErrorCode$1.FileTooSmall] = "FileTooSmall";
12
- ErrorCode[ErrorCode["FileInvalidType"] = ErrorCode$1.FileInvalidType] = "FileInvalidType";
13
- ErrorCode[ErrorCode["TooManyFiles"] = ErrorCode$1.TooManyFiles] = "TooManyFiles";
14
- ErrorCode["Unknown"] = "unknown";
15
- })(ErrorCode || (ErrorCode = {}));
16
- function getFlatErrorCodes(fileRejections) {
17
- return fileRejections.flatMap((fileRejection)=>fileRejection.errors.map((error)=>error.code));
18
- }
19
- function getErrorCode(errorCodes) {
20
- if (errorCodes.includes(ErrorCode$1.FileTooLarge)) {
21
- return ErrorCode.FileTooLarge;
22
- }
23
- if (errorCodes.includes(ErrorCode$1.FileTooSmall)) {
24
- return ErrorCode.FileTooSmall;
25
- }
26
- if (errorCodes.includes(ErrorCode$1.FileInvalidType)) {
27
- return ErrorCode.FileInvalidType;
28
- }
29
- if (errorCodes.includes(ErrorCode$1.TooManyFiles)) {
30
- return ErrorCode.TooManyFiles;
31
- }
32
- return "unknown";
33
- }
34
- function mapFileRejectionsToErrorCode(fileRejections) {
35
- return getErrorCode(getFlatErrorCodes(fileRejections));
36
- }
37
-
38
- function _extends() {
39
- _extends = Object.assign || function assign(target) {
40
- for(var i = 1; i < arguments.length; i++){
41
- var source = arguments[i];
42
- for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
43
- }
44
- return target;
45
- };
46
- return _extends.apply(this, arguments);
47
- }
48
-
49
- /**
50
- * Uploads an image file using provided upload parameters.
51
- *
52
- * Handles file upload by calling the getUploadParams function to retrieve upload configuration,
53
- * then performs a fetch request to upload the file. Returns early if the image is already uploaded.
54
- *
55
- * @param image - Image file with ID or already uploaded image with URL
56
- * @param getUploadParams - Function that returns upload parameters (URI, method, headers) for the image
57
- * @returns Promise resolving to uploaded image with URL
58
- * @throws {Error} When upload params are not defined, image is not defined, or upload fails
59
- *
60
- * @example
61
- * ```typescript
62
- * import { tryUploadWithUploadParams } from "@leancodepl/image-uploader";
63
- *
64
- * const uploadedImage = await tryUploadWithUploadParams(image, async (img) => ({
65
- * uri: "https://api.example.com/upload",
66
- * method: "POST",
67
- * requiredHeaders: { "Content-Type": "image/jpeg" }
68
- * }));
69
- * ```
70
- */ async function tryUploadWithUploadParams(image, getUploadParams) {
71
- if ("url" in image) {
72
- return image;
73
- }
74
- if (!image.originalFile) {
75
- throw new Error("Image is not defined");
76
- }
77
- try {
78
- const uploadParams = await getUploadParams(image);
79
- if (!uploadParams) {
80
- throw new Error("Upload params are not defined");
81
- }
82
- const { uri, method, requiredHeaders } = uploadParams;
83
- const response = await fetch(uri, {
84
- method,
85
- headers: requiredHeaders,
86
- body: image.originalFile
87
- });
88
- if (!response.ok) {
89
- throw new Error("Failed to upload image");
90
- }
91
- return _extends({}, image, {
92
- url: uri
93
- });
94
- } catch (e) {
95
- throw new Error("Failed to upload image");
96
- }
97
- }
98
-
99
- const defaultAccept = {
100
- "image/*": []
101
- };
102
- const defaultCrop = {
103
- x: 0,
104
- y: 0
105
- };
106
- const defaultZoom = 1;
107
- const defaultRotation = 0;
108
-
109
- const UploadImagesContext = /*#__PURE__*/ createContext(undefined);
110
- function UploadImagesProvider({ children, uploader }) {
111
- return /*#__PURE__*/ jsx(UploadImagesContext.Provider, {
112
- value: uploader,
113
- children: children
114
- });
115
- }
116
- function useUploadImagesContext() {
117
- const context = useContext(UploadImagesContext);
118
- if (!context) {
119
- throw new Error("All UploadImages components must be wrapped in an UploadImages.Root component");
120
- }
121
- return context;
122
- }
123
-
124
- /**
125
- * Image cropper component with editing controls.
126
- *
127
- * Provides image cropping functionality with zoom, rotation, and crop area controls.
128
- * Processes cropped images and integrates with the upload state management.
129
- *
130
- * @param children - Content or render function receiving cropper controls
131
- * @returns JSX element with cropper editing interface
132
- * @throws {Error} When cropper config is not defined in context
133
- *
134
- * @example
135
- * ```typescript
136
- * import { UploadImages } from "@leancodepl/image-uploader";
137
- *
138
- * <UploadImages.Cropper>
139
- * {({ zoom, rotation, setZoom, setRotation, accept, close }) => (
140
- * <div>
141
- * <UploadImages.CropperEditor />
142
- * <input
143
- * type="range"
144
- * value={zoom}
145
- * onChange={(e) => setZoom(Number(e.target.value))}
146
- * />
147
- * <button onClick={accept}>Accept</button>
148
- * <button onClick={close}>Cancel</button>
149
- * </div>
150
- * )}
151
- * </UploadImages.Cropper>
152
- * ```
153
- */ function UploadImagesCropper({ children }) {
154
- const { cropper } = useUploadImagesContext();
155
- if (!cropper) {
156
- throw new Error("Cropper config is not defined");
157
- }
158
- const { file, editorImage, acceptImage, closeImage, config, cropArea, zoom, rotation, setCropArea, setCrop, setZoom, setRotation } = cropper;
159
- const close = useCallback(()=>{
160
- closeImage();
161
- setCrop(defaultCrop);
162
- setZoom(defaultZoom);
163
- setRotation(defaultRotation);
164
- setCropArea(undefined);
165
- }, [
166
- closeImage,
167
- setCrop,
168
- setCropArea,
169
- setRotation,
170
- setZoom
171
- ]);
172
- const accept = useCallback(()=>{
173
- if (!editorImage) return;
174
- const canvas = document.createElement("canvas");
175
- const canvas2 = document.createElement("canvas");
176
- const ctx = canvas.getContext("2d");
177
- const ctx2 = canvas2.getContext("2d");
178
- const img = new Image();
179
- img.onload = function() {
180
- const { naturalWidth: imgWidth, naturalHeight: imgHeight } = img;
181
- const angle = rotation * (Math.PI / 180);
182
- const sine = Math.abs(Math.sin(angle));
183
- const cosine = Math.abs(Math.cos(angle));
184
- const squareWidth = imgWidth * cosine + imgHeight * sine;
185
- const squareHeight = imgHeight * cosine + imgWidth * sine;
186
- canvas.width = squareWidth;
187
- canvas.height = squareHeight;
188
- ctx.fillStyle = "#fff";
189
- ctx.fillRect(0, 0, squareWidth, squareHeight);
190
- const squareHalfWidth = squareWidth / 2;
191
- const squareHalfHeight = squareHeight / 2;
192
- ctx.translate(squareHalfWidth, squareHalfHeight);
193
- ctx.rotate(angle);
194
- ctx.translate(-squareHalfWidth, -squareHalfHeight);
195
- const imgX = (squareWidth - imgWidth) / 2;
196
- const imgY = (squareHeight - imgHeight) / 2;
197
- ctx.drawImage(img, 0, 0, imgWidth, imgHeight, imgX, imgY, imgWidth, imgHeight);
198
- var _cropArea_width, _config_maxWidth;
199
- canvas2.width = Math.min(((_cropArea_width = cropArea == null ? void 0 : cropArea.width) != null ? _cropArea_width : 100) / 100 * squareWidth, (_config_maxWidth = config.maxWidth) != null ? _config_maxWidth : Number.POSITIVE_INFINITY);
200
- var _cropArea_height, _config_maxHeight;
201
- canvas2.height = Math.min(((_cropArea_height = cropArea == null ? void 0 : cropArea.height) != null ? _cropArea_height : 100) / 100 * squareHeight, (_config_maxHeight = config.maxHeight) != null ? _config_maxHeight : Number.POSITIVE_INFINITY);
202
- var _cropArea_x, _cropArea_y, _cropArea_width1, _cropArea_height1;
203
- ctx2.drawImage(canvas, ((_cropArea_x = cropArea == null ? void 0 : cropArea.x) != null ? _cropArea_x : 0) / 100 * squareWidth, ((_cropArea_y = cropArea == null ? void 0 : cropArea.y) != null ? _cropArea_y : 0) / 100 * squareHeight, ((_cropArea_width1 = cropArea == null ? void 0 : cropArea.width) != null ? _cropArea_width1 : 100) / 100 * squareWidth, ((_cropArea_height1 = cropArea == null ? void 0 : cropArea.height) != null ? _cropArea_height1 : 100) / 100 * squareHeight, 0, 0, canvas2.width, canvas2.height);
204
- canvas2.toBlob((blob)=>{
205
- if (!file) {
206
- return;
207
- }
208
- var _file_originalFile_name, _file_originalFile_type;
209
- const newFile = new File([
210
- blob
211
- ], (_file_originalFile_name = file.originalFile.name) != null ? _file_originalFile_name : "image.png", {
212
- type: (_file_originalFile_type = file.originalFile.type) != null ? _file_originalFile_type : "image/png"
213
- });
214
- const uploadFile = {
215
- originalFile: newFile,
216
- id: file.id
217
- };
218
- acceptImage(uploadFile);
219
- });
220
- close();
221
- };
222
- img.src = editorImage;
223
- }, [
224
- close,
225
- config,
226
- cropArea,
227
- file,
228
- editorImage,
229
- rotation,
230
- acceptImage
231
- ]);
232
- return typeof children === "function" ? children({
233
- zoom,
234
- rotation,
235
- setZoom,
236
- setRotation,
237
- accept,
238
- close
239
- }) : children;
240
- }
241
-
242
- function _object_without_properties_loose(source, excluded) {
243
- if (source == null) return {};
244
- var target = {};
245
- var sourceKeys = Object.keys(source);
246
- var key, i;
247
- for(i = 0; i < sourceKeys.length; i++){
248
- key = sourceKeys[i];
249
- if (excluded.indexOf(key) >= 0) continue;
250
- target[key] = source[key];
251
- }
252
- return target;
253
- }
254
-
255
- /**
256
- * Visual editor component for image cropping.
257
- *
258
- * Renders the interactive crop editor interface using `"react-easy-crop"`.
259
- * Provides visual feedback for crop area, zoom, and rotation adjustments.
260
- *
261
- * @param style - CSS style object, merged with default positioning styles
262
- * @param props - Additional HTML div attributes
263
- * @returns JSX element with interactive crop editor
264
- * @throws {Error} When cropper config is not defined in context
265
- *
266
- * @example
267
- * ```typescript
268
- * import { UploadImages } from "@leancodepl/image-uploader";
269
- *
270
- * <UploadImages.Cropper>
271
- * {({ zoom, setZoom, rotation, setRotation, accept, close }) => (
272
- * <div>
273
- * <UploadImages.CropperEditor />
274
- * <div>
275
- * <label>Zoom: <input type="range" value={zoom} onChange={(e) => setZoom(Number(e.target.value))} /></label>
276
- * <button onClick={accept}>Accept</button>
277
- * <button onClick={close}>Cancel</button>
278
- * </div>
279
- * </div>
280
- * )}
281
- * </UploadImages.Cropper>
282
- * ```
283
- */ function UploadImagesCropperEditor(_param) {
284
- var { style } = _param, props = _object_without_properties_loose(_param, [
285
- "style"
286
- ]);
287
- const { cropper } = useUploadImagesContext();
288
- if (!cropper) {
289
- throw new Error("Cropper config is not defined");
290
- }
291
- const { editorImage, config, zoom, rotation, crop, setCropArea, setCrop, setZoom, setRotation } = cropper;
292
- return /*#__PURE__*/ jsx("div", _extends({}, props, {
293
- style: _extends({
294
- position: "relative",
295
- width: "100%",
296
- height: "300px"
297
- }, style),
298
- children: /*#__PURE__*/ jsx(EasyCrop, {
299
- aspect: config.aspect,
300
- crop: crop,
301
- image: editorImage,
302
- rotation: rotation,
303
- zoom: zoom,
304
- onCropChange: setCrop,
305
- onCropComplete: setCropArea,
306
- onRotationChange: setRotation,
307
- onZoomChange: setZoom
308
- })
309
- }));
310
- }
311
-
312
- async function getImagePreviewData(file) {
313
- return file ? await getBase64(file) : "";
314
- }
315
- const getBase64 = (file)=>new Promise((resolve, reject)=>{
316
- const reader = new FileReader();
317
- reader.readAsDataURL(file);
318
- reader.onload = ()=>resolve(String(reader.result));
319
- reader.onerror = (error)=>reject(error);
320
- });
321
-
322
- /**
323
- * Individual file item component with preview and removal functionality.
324
- *
325
- * Displays a single uploaded file with preview image generation and removal capability.
326
- * Automatically generates image preview data and provides remove function to children.
327
- *
328
- * @param children - Content or render function receiving file, preview, and remove function
329
- * @param file - File object with ID to display
330
- * @param props - Additional HTML div attributes
331
- * @returns JSX element for individual file with preview and controls
332
- *
333
- * @example
334
- * ```typescript
335
- * import { UploadImages } from "@leancodepl/image-uploader";
336
- *
337
- * <UploadImages.File file={fileWithId}>
338
- * {({ file, preview, remove }) => (
339
- * <div>
340
- * <img src={preview} alt={file.originalFile.name} />
341
- * <p>{file.originalFile.name}</p>
342
- * <button onClick={remove}>Remove</button>
343
- * </div>
344
- * )}
345
- * </UploadImages.File>
346
- * ```
347
- */ function UploadImagesFileItem(_param) {
348
- var { children, file } = _param, props = _object_without_properties_loose(_param, [
349
- "children",
350
- "file"
351
- ]);
352
- const { removeFile } = useUploadImagesContext();
353
- const [previewData, setPreviewData] = useState();
354
- useEffect(()=>{
355
- const loadPreview = async ()=>{
356
- const preview = await getImagePreviewData(file.originalFile);
357
- setPreviewData(preview);
358
- };
359
- loadPreview();
360
- }, [
361
- file.originalFile
362
- ]);
363
- return /*#__PURE__*/ jsx("div", _extends({}, props, {
364
- children: typeof children === "function" ? children({
365
- file,
366
- preview: previewData,
367
- remove: ()=>removeFile(file.id)
368
- }) : children
369
- }));
370
- }
371
-
372
- /**
373
- * Container component for displaying uploaded files.
374
- *
375
- * Renders a container for uploaded files and provides current file list to children.
376
- * Used to display and manage the collection of uploaded images.
377
- *
378
- * @param children - Content or render function receiving files array
379
- * @param props - Additional HTML div attributes
380
- * @returns JSX element containing uploaded files
381
- *
382
- * @example
383
- * ```typescript
384
- * import { UploadImages } from "@leancodepl/image-uploader";
385
- *
386
- * <UploadImages.Files>
387
- * {({ files }) => (
388
- * <div>
389
- * {files?.map(file => (
390
- * <UploadImages.File key={file.id} file={file}>
391
- * {({ preview, remove }) => (
392
- * <div>
393
- * <img src={preview} alt="Preview" />
394
- * <button onClick={remove}>Remove</button>
395
- * </div>
396
- * )}
397
- * </UploadImages.File>
398
- * ))}
399
- * </div>
400
- * )}
401
- * </UploadImages.Files>
402
- * ```
403
- */ function UploadImagesFiles(_param) {
404
- var { children } = _param, props = _object_without_properties_loose(_param, [
405
- "children"
406
- ]);
407
- const { value } = useUploadImagesContext();
408
- return /*#__PURE__*/ jsx("div", _extends({}, props, {
409
- children: typeof children === "function" ? children({
410
- files: value
411
- }) : children
412
- }));
413
- }
414
-
415
- /**
416
- * Root wrapper component for image upload functionality.
417
- *
418
- * Provides upload context to all child UploadImages components and renders a div container.
419
- * Must wrap all other UploadImages components to provide shared state.
420
- *
421
- * @param uploader - Upload state and functions from `useUploadImages` hook
422
- * @param props - Additional HTML div attributes
423
- * @returns JSX element wrapping children with upload context
424
- *
425
- * @example
426
- * ```typescript
427
- * import { UploadImages, useUploadImages } from "@leancodepl/image-uploader";
428
- *
429
- * const uploader = useUploadImages({ value: files, onChange: setFiles });
430
- *
431
- * <UploadImages.Root uploader={uploader}>
432
- * <UploadImages.Zone>Drop files here</UploadImages.Zone>
433
- * <UploadImages.Files />
434
- * </UploadImages.Root>
435
- * ```
436
- */ function UploadImagesRoot(_param) {
437
- var { uploader } = _param, props = _object_without_properties_loose(_param, [
438
- "uploader"
439
- ]);
440
- return /*#__PURE__*/ jsx(UploadImagesProvider, {
441
- uploader: uploader,
442
- children: /*#__PURE__*/ jsx("div", _extends({}, props))
443
- });
444
- }
445
-
446
- /**
447
- * Drag-and-drop zone component for file uploads.
448
- *
449
- * Creates an interactive drop zone with file input capabilities. Supports both click-to-select
450
- * and drag-and-drop file uploads. Provides drag state to children for visual feedback.
451
- *
452
- * @param children - Content or render function receiving drag state props
453
- * @param props - Additional HTML div attributes
454
- * @returns JSX element with drag-and-drop upload functionality
455
- *
456
- * @example
457
- * ```typescript
458
- * import { UploadImages } from "@leancodepl/image-uploader";
459
- *
460
- * <UploadImages.Zone>
461
- * {({ isDragActive, isFocused }) => (
462
- * <div className={isDragActive ? "drag-active" : ""}>
463
- * {isDragActive ? "Drop files here" : "Click or drag files to upload"}
464
- * </div>
465
- * )}
466
- * </UploadImages.Zone>
467
- * ```
468
- */ function UploadImagesZone(_param) {
469
- var { children } = _param, props = _object_without_properties_loose(_param, [
470
- "children"
471
- ]);
472
- const { dropzone: { getRootProps, getInputProps, isDragActive, isFocused, isFileDialogActive } } = useUploadImagesContext();
473
- return /*#__PURE__*/ jsxs("div", _extends({}, getRootProps(), props, {
474
- children: [
475
- /*#__PURE__*/ jsx("input", _extends({}, getInputProps())),
476
- typeof children === "function" ? children({
477
- isDragActive,
478
- isFocused,
479
- isFileDialogActive
480
- }) : children
481
- ]
482
- }));
483
- }
484
-
485
- const UploadImages = {
486
- Root: UploadImagesRoot,
487
- Zone: UploadImagesZone,
488
- Files: UploadImagesFiles,
489
- File: UploadImagesFileItem,
490
- Cropper: UploadImagesCropper,
491
- CropperEditor: UploadImagesCropperEditor
492
- };
493
-
494
- function isExactFile(a, b) {
495
- return a.name === b.name && a.size === b.size && a.lastModified === b.lastModified;
496
- }
497
-
498
- function useCropper({ value, onChange }) {
499
- const [fileQueue, setFileQueue] = useState([]);
500
- const [editorImage, setEditorImage] = useState();
501
- const [cropArea, setCropArea] = useState();
502
- const [crop, setCrop] = useState(defaultCrop);
503
- const [zoom, setZoom] = useState(defaultZoom);
504
- const [rotation, setRotation] = useState(defaultRotation);
505
- const file = fileQueue.at(0);
506
- const isOpen = !!file;
507
- useSyncState(file, (newCropperFile)=>{
508
- setEditorImage(undefined);
509
- if (!newCropperFile) {
510
- return;
511
- }
512
- const reader = new FileReader();
513
- reader.addEventListener("load", ()=>{
514
- if (typeof reader.result === "string") {
515
- setEditorImage(reader.result);
516
- }
517
- });
518
- reader.readAsDataURL(newCropperFile.originalFile);
519
- });
520
- const closeImage = useCallback(()=>{
521
- setFileQueue(fileQueue.filter(({ id })=>id !== (file == null ? void 0 : file.id)));
522
- }, [
523
- fileQueue,
524
- file == null ? void 0 : file.id
525
- ]);
526
- const acceptImage = useCallback((file)=>onChange == null ? void 0 : onChange([
527
- ...value != null ? value : [],
528
- file
529
- ]), [
530
- onChange,
531
- value
532
- ]);
533
- return {
534
- fileQueue,
535
- file,
536
- editorImage,
537
- cropArea,
538
- crop,
539
- zoom,
540
- rotation,
541
- isOpen,
542
- setFileQueue,
543
- setEditorImage,
544
- setCropArea,
545
- setCrop,
546
- setZoom,
547
- setRotation,
548
- closeImage,
549
- acceptImage
550
- };
551
- }
552
-
553
- /**
554
- * Manages image upload state and provides drag-and-drop functionality.
555
- *
556
- * Creates a complete image upload solution with file validation, drag-and-drop support,
557
- * optional cropping, and duplicate detection. Returns upload state and control functions.
558
- *
559
- * @param value - Current array of uploaded files with IDs
560
- * @param accept - File types to accept (defaults to image types)
561
- * @param cropper - Optional cropper configuration for image editing
562
- * @param onError - Callback for handling upload errors
563
- * @param onChange - Callback when file list changes
564
- * @returns Upload state and control functions including dropzone props
565
- *
566
- * @example
567
- * ```typescript
568
- * import { useUploadImages } from "@leancodepl/image-uploader";
569
- *
570
- * const uploader = useUploadImages({
571
- * value: files,
572
- * onChange: setFiles,
573
- * onError: (error) => console.error("Upload error:", error),
574
- * accept: { "image/*": [".jpg", ".png"] }
575
- * });
576
- * ```
577
- */ function useUploadImages({ value, accept = defaultAccept, cropper: cropperConfig, onError, onChange }) {
578
- const _useCropper = useCropper({
579
- value,
580
- onChange
581
- }), { setFileQueue: setCropperFileQueue } = _useCropper, cropperProps = _object_without_properties_loose(_useCropper, [
582
- "setFileQueue"
583
- ]);
584
- const handleNewFiles = useCallback((newFiles)=>{
585
- if (cropperConfig) {
586
- setCropperFileQueue(newFiles);
587
- } else {
588
- onChange == null ? void 0 : onChange([
589
- ...value != null ? value : [],
590
- ...newFiles
591
- ]);
592
- }
593
- }, [
594
- cropperConfig,
595
- onChange,
596
- value,
597
- setCropperFileQueue
598
- ]);
599
- const addFiles = useCallback((newFiles)=>{
600
- const uniqueNewFiles = newFiles.filter((newFile)=>!(value == null ? void 0 : value.some((existingFile)=>isExactFile(existingFile.originalFile, newFile.originalFile))));
601
- handleNewFiles(uniqueNewFiles);
602
- }, [
603
- handleNewFiles,
604
- value
605
- ]);
606
- const removeFile = useCallback((id)=>{
607
- var _value_filter;
608
- onChange == null ? void 0 : onChange((_value_filter = value == null ? void 0 : value.filter((f)=>f.id !== id)) != null ? _value_filter : []);
609
- }, [
610
- value,
611
- onChange
612
- ]);
613
- const clearFiles = useCallback(()=>{
614
- onChange == null ? void 0 : onChange([]);
615
- }, [
616
- onChange
617
- ]);
618
- const handleDrop = useCallback((acceptedFiles)=>{
619
- addFiles(acceptedFiles.map((file)=>({
620
- originalFile: file,
621
- id: v4()
622
- })));
623
- }, [
624
- addFiles
625
- ]);
626
- const handleDropRejected = useCallback((fileRejections)=>{
627
- onError == null ? void 0 : onError(mapFileRejectionsToErrorCode(fileRejections));
628
- }, [
629
- onError
630
- ]);
631
- const dropzone = useDropzone({
632
- onDrop: handleDrop,
633
- onDropRejected: handleDropRejected,
634
- accept
635
- });
636
- const uploader = {
637
- value,
638
- dropzone,
639
- addFiles,
640
- removeFile,
641
- clearFiles,
642
- cropper: cropperConfig && _extends({
643
- config: cropperConfig
644
- }, cropperProps)
645
- };
646
- return _extends({}, uploader, {
647
- uploader
648
- });
649
- }
650
-
651
- export { ErrorCode, UploadImages, tryUploadWithUploadParams, useUploadImages };
package/src/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export { ErrorCode } from "./lib/_utils/errors";
2
- export * from "./lib/_utils/tryUploadWithUploadParams";
3
- export * from "./lib/UploadImages";
4
- export * from "./lib/types";
5
- export { useUploadImages, type UseUploadImagesProps } from "./lib/_hooks/useUploadImages";
@@ -1,20 +0,0 @@
1
- import { UploadImagesCropper } from "./Cropper";
2
- import { UploadImagesCropperEditor } from "./CropperEditor";
3
- import { UploadImagesFileItem } from "./File";
4
- import { UploadImagesFiles } from "./Files";
5
- import { UploadImagesRoot } from "./Root";
6
- import { UploadImagesZone } from "./Zone";
7
- export declare const UploadImages: {
8
- Root: typeof UploadImagesRoot;
9
- Zone: typeof UploadImagesZone;
10
- Files: typeof UploadImagesFiles;
11
- File: typeof UploadImagesFileItem;
12
- Cropper: typeof UploadImagesCropper;
13
- CropperEditor: typeof UploadImagesCropperEditor;
14
- };
15
- export type { UploadImagesFileItemProps } from "./File";
16
- export type { UploadImagesFilesProps } from "./Files";
17
- export type { UploadImagesRootProps } from "./Root";
18
- export type { UploadImagesZoneProps } from "./Zone";
19
- export type { UploadImagesCropperProps } from "./Cropper";
20
- export type { UploadImagesCropperEditorProps } from "./CropperEditor";