@pagamio/frontend-commons-lib 0.8.349 → 0.8.350
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.
|
@@ -13,6 +13,12 @@ export interface ImageUploaderProps {
|
|
|
13
13
|
showPreview?: boolean;
|
|
14
14
|
value?: string;
|
|
15
15
|
onChange?: (url: string | null) => void;
|
|
16
|
+
/**
|
|
17
|
+
* When true (default) the image is resized to 1920×1920 and converted
|
|
18
|
+
* to WebP before upload — correct for photos. Set false for assets that
|
|
19
|
+
* must keep their exact bytes/dimensions
|
|
20
|
+
*/
|
|
21
|
+
processImage?: boolean;
|
|
16
22
|
}
|
|
17
23
|
declare const ImageUploader: React.FC<ImageUploaderProps>;
|
|
18
24
|
export default ImageUploader;
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Image as ImageIcon, Loader2, Upload, X } from 'lucide-react';
|
|
3
3
|
import { useDropzone } from 'react-dropzone';
|
|
4
|
-
import { useCallback, useState } from 'react';
|
|
4
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
5
5
|
import { Button, cn, useToast } from '../..';
|
|
6
6
|
import { useImageUpload } from '../../shared/hooks/useImageUpload';
|
|
7
7
|
import { Progress } from './Progress';
|
|
8
|
+
const PHOTO_FILE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
|
9
|
+
const RAW_FILE_TYPES = ['image/png', 'image/svg+xml', 'image/webp', 'image/x-icon', 'image/vnd.microsoft.icon'];
|
|
8
10
|
const ImageUploader = ({ project, env, endpoint, onUploadSuccess, onError, className, disabled = false, maxFileSize = 5 * 1024 * 1024, // 5MB default
|
|
9
|
-
acceptedFileTypes
|
|
11
|
+
acceptedFileTypes, placeholder = 'Click to upload or drag and drop an image', showPreview = true, value, onChange, processImage = true, }) => {
|
|
12
|
+
const resolvedFileTypes = useMemo(() => acceptedFileTypes ?? (processImage ? PHOTO_FILE_TYPES : RAW_FILE_TYPES), [acceptedFileTypes, processImage]);
|
|
10
13
|
const [previewUrl, setPreviewUrl] = useState(value || null);
|
|
11
14
|
const [isUploading, setIsUploading] = useState(false);
|
|
12
15
|
const [uploadProgress, setUploadProgress] = useState(0);
|
|
13
16
|
const [error, setError] = useState(null);
|
|
14
17
|
const { addToast } = useToast();
|
|
15
|
-
const { uploadFile } = useImageUpload({ project, env, endpoint });
|
|
18
|
+
const { uploadFile } = useImageUpload({ project, env, endpoint, processImage });
|
|
16
19
|
const handleFileUpload = async (file) => {
|
|
17
20
|
if (disabled)
|
|
18
21
|
return;
|
|
@@ -21,8 +24,8 @@ acceptedFileTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], plac
|
|
|
21
24
|
setUploadProgress(0);
|
|
22
25
|
try {
|
|
23
26
|
// Validate file type
|
|
24
|
-
if (!
|
|
25
|
-
throw new Error(`File type not supported. Accepted types: ${
|
|
27
|
+
if (!resolvedFileTypes.includes(file.type)) {
|
|
28
|
+
throw new Error(`File type not supported. Accepted types: ${resolvedFileTypes.join(', ')}`);
|
|
26
29
|
}
|
|
27
30
|
// Validate file size
|
|
28
31
|
if (file.size > maxFileSize) {
|
|
@@ -76,10 +79,10 @@ acceptedFileTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], plac
|
|
|
76
79
|
if (file) {
|
|
77
80
|
handleFileUpload(file);
|
|
78
81
|
}
|
|
79
|
-
}, [disabled,
|
|
82
|
+
}, [disabled, resolvedFileTypes, maxFileSize]);
|
|
80
83
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
81
84
|
onDrop,
|
|
82
|
-
accept:
|
|
85
|
+
accept: resolvedFileTypes.reduce((acc, type) => {
|
|
83
86
|
acc[type] = [];
|
|
84
87
|
return acc;
|
|
85
88
|
}, {}),
|
|
@@ -91,6 +94,6 @@ acceptedFileTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], plac
|
|
|
91
94
|
setError(null);
|
|
92
95
|
onChange?.(null);
|
|
93
96
|
};
|
|
94
|
-
return (_jsxs("div", { className: cn('w-full', className), children: [previewUrl && showPreview ? (_jsxs("div", { className: "relative mb-4", children: [_jsx("img", { src: previewUrl, alt: "Preview", className: "max-h-64 w-full rounded-lg object-contain border border-border" }), !isUploading && (_jsx(Button, { type: "button", variant: "destructive", size: "sm", className: "absolute top-2 right-2", onClick: handleRemove, children: _jsx(X, { className: "h-4 w-4" }) }))] })) : (_jsxs("div", { ...getRootProps(), className: cn('border-2 border-dashed border-input rounded-lg p-8 text-center cursor-pointer transition-colors hover:border-muted-foreground', isDragActive && 'border-primary bg-primary/10', disabled && 'cursor-not-allowed opacity-50', error && 'border-red-500 bg-red-50'), children: [_jsx("input", { ...getInputProps() }), isUploading ? (_jsxs("div", { className: "flex flex-col items-center space-y-2", children: [_jsx(Loader2, { className: "h-8 w-8 animate-spin text-primary" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Uploading image..." }), _jsx(Progress, { value: uploadProgress, className: "w-full max-w-xs" })] })) : (_jsxs("div", { className: "flex flex-col items-center space-y-2", children: [isDragActive ? (_jsx(Upload, { className: "h-8 w-8 text-primary" })) : (_jsx(ImageIcon, { className: "h-8 w-8 text-muted-foreground" })), _jsx("p", { className: "text-sm text-muted-foreground", children: isDragActive ? 'Drop the image here' : placeholder }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Supported formats: ",
|
|
97
|
+
return (_jsxs("div", { className: cn('w-full', className), children: [previewUrl && showPreview ? (_jsxs("div", { className: "relative mb-4", children: [_jsx("img", { src: previewUrl, alt: "Preview", className: "max-h-64 w-full rounded-lg object-contain border border-border" }), !isUploading && (_jsx(Button, { type: "button", variant: "destructive", size: "sm", className: "absolute top-2 right-2", onClick: handleRemove, children: _jsx(X, { className: "h-4 w-4" }) }))] })) : (_jsxs("div", { ...getRootProps(), className: cn('border-2 border-dashed border-input rounded-lg p-8 text-center cursor-pointer transition-colors hover:border-muted-foreground', isDragActive && 'border-primary bg-primary/10', disabled && 'cursor-not-allowed opacity-50', error && 'border-red-500 bg-red-50'), children: [_jsx("input", { ...getInputProps() }), isUploading ? (_jsxs("div", { className: "flex flex-col items-center space-y-2", children: [_jsx(Loader2, { className: "h-8 w-8 animate-spin text-primary" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Uploading image..." }), _jsx(Progress, { value: uploadProgress, className: "w-full max-w-xs" })] })) : (_jsxs("div", { className: "flex flex-col items-center space-y-2", children: [isDragActive ? (_jsx(Upload, { className: "h-8 w-8 text-primary" })) : (_jsx(ImageIcon, { className: "h-8 w-8 text-muted-foreground" })), _jsx("p", { className: "text-sm text-muted-foreground", children: isDragActive ? 'Drop the image here' : placeholder }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Supported formats: ", resolvedFileTypes.map((type) => type.split('/')[1]).join(', ')] }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Max size: ", Math.round(maxFileSize / 1024 / 1024), "MB"] })] }))] })), error && _jsx("p", { className: "mt-2 text-sm text-red-600", children: error })] }));
|
|
95
98
|
};
|
|
96
99
|
export default ImageUploader;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagamio/frontend-commons-lib",
|
|
3
3
|
"description": "Pagamio library for Frontend reusable components like the form engine and table container",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.350",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|