allaw-ui 5.1.0 → 5.1.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.
@@ -152,7 +152,7 @@
152
152
  }
153
153
 
154
154
  .optionsSmall {
155
- z-index: 10;
155
+ z-index: 1000;
156
156
  display: flex;
157
157
  }
158
158
  }
@@ -6,6 +6,21 @@ export interface FileUploaderProps {
6
6
  enableDragAndDrop?: boolean;
7
7
  enableCropping?: boolean;
8
8
  cropShape?: "circle" | "square" | "banner";
9
+ clientSideCrop?: boolean;
10
+ cropOutputDimensions?: {
11
+ square?: {
12
+ width: number;
13
+ height: number;
14
+ };
15
+ circle?: {
16
+ width: number;
17
+ height: number;
18
+ };
19
+ banner?: {
20
+ width: number;
21
+ height: number;
22
+ };
23
+ };
9
24
  iconUrl?: string;
10
25
  descriptionParts?: {
11
26
  beforeLink: string;
@@ -41,17 +41,21 @@ import ImageCropperModal from "./ImageCropperModal";
41
41
  import IconButton from "../../atoms/buttons/IconButton";
42
42
  import TertiaryButton from "../../atoms/buttons/TertiaryButton";
43
43
  var FileUploader = function (_a) {
44
- var acceptedExtensions = _a.acceptedExtensions, maxFileSizeMB = _a.maxFileSizeMB, _b = _a.enableDragAndDrop, enableDragAndDrop = _b === void 0 ? true : _b, _c = _a.enableCropping, enableCropping = _c === void 0 ? false : _c, _d = _a.cropShape, cropShape = _d === void 0 ? "square" : _d, iconUrl = _a.iconUrl, descriptionParts = _a.descriptionParts, onFileRead = _a.onFileRead, onFileRemove = _a.onFileRemove, _e = _a.uploadProgress, uploadProgress = _e === void 0 ? 0 : _e, _f = _a.isLoading, isLoading = _f === void 0 ? false : _f, _g = _a.autoManageProgress, autoManageProgress = _g === void 0 ? false : _g, _h = _a.progressSteps, progressSteps = _h === void 0 ? 10 : _h, _j = _a.progressInterval, progressInterval = _j === void 0 ? 500 : _j, _k = _a.errorMessage, errorMessage = _k === void 0 ? null : _k, _l = _a.buttonLabel, buttonLabel = _l === void 0 ? "Choisir un fichier" : _l, _m = _a.acceptedLabel, acceptedLabel = _m === void 0 ? "Format accepté :" : _m, _o = _a.maxSizeLabel, maxSizeLabel = _o === void 0 ? "Taille maximale :" : _o, fileName = _a.fileName, fileSize = _a.fileSize, _p = _a.filePresentationLabel, filePresentationLabel = _p === void 0 ? "Voici votre fichier." : _p, initialFile = _a.initialFile, initialPreviewUrl = _a.initialPreviewUrl, initialCropMetadata = _a.initialCropMetadata, originalFileName = _a.originalFileName;
45
- var _q = useState(initialFile || null), selectedFile = _q[0], setSelectedFile = _q[1];
46
- var _r = useState(null), fileContent = _r[0], setFileContent = _r[1];
47
- var _s = useState(false), isHovering = _s[0], setIsHovering = _s[1];
48
- var _t = useState(false), showCropper = _t[0], setShowCropper = _t[1];
49
- var _u = useState(initialPreviewUrl || null), previewUrl = _u[0], setPreviewUrl = _u[1];
50
- var _v = useState(initialCropMetadata || null), cropMetadata = _v[0], setCropMetadata = _v[1];
51
- var _w = useState(0), internalProgress = _w[0], setInternalProgress = _w[1];
44
+ var acceptedExtensions = _a.acceptedExtensions, maxFileSizeMB = _a.maxFileSizeMB, _b = _a.enableDragAndDrop, enableDragAndDrop = _b === void 0 ? true : _b, _c = _a.enableCropping, enableCropping = _c === void 0 ? false : _c, _d = _a.cropShape, cropShape = _d === void 0 ? "square" : _d, _e = _a.clientSideCrop, clientSideCrop = _e === void 0 ? false : _e, _f = _a.cropOutputDimensions, cropOutputDimensions = _f === void 0 ? {
45
+ square: { width: 200, height: 200 },
46
+ circle: { width: 200, height: 200 },
47
+ banner: { width: 1200, height: 400 },
48
+ } : _f, iconUrl = _a.iconUrl, descriptionParts = _a.descriptionParts, onFileRead = _a.onFileRead, onFileRemove = _a.onFileRemove, _g = _a.uploadProgress, uploadProgress = _g === void 0 ? 0 : _g, _h = _a.isLoading, isLoading = _h === void 0 ? false : _h, _j = _a.autoManageProgress, autoManageProgress = _j === void 0 ? false : _j, _k = _a.progressSteps, progressSteps = _k === void 0 ? 10 : _k, _l = _a.progressInterval, progressInterval = _l === void 0 ? 500 : _l, _m = _a.errorMessage, errorMessage = _m === void 0 ? null : _m, _o = _a.buttonLabel, buttonLabel = _o === void 0 ? "Choisir un fichier" : _o, _p = _a.acceptedLabel, acceptedLabel = _p === void 0 ? "Format accepté :" : _p, _q = _a.maxSizeLabel, maxSizeLabel = _q === void 0 ? "Taille maximale :" : _q, fileName = _a.fileName, fileSize = _a.fileSize, _r = _a.filePresentationLabel, filePresentationLabel = _r === void 0 ? "Voici votre fichier." : _r, initialFile = _a.initialFile, initialPreviewUrl = _a.initialPreviewUrl, initialCropMetadata = _a.initialCropMetadata, originalFileName = _a.originalFileName;
49
+ var _s = useState(initialFile || null), selectedFile = _s[0], setSelectedFile = _s[1];
50
+ var _t = useState(null), fileContent = _t[0], setFileContent = _t[1];
51
+ var _u = useState(false), isHovering = _u[0], setIsHovering = _u[1];
52
+ var _v = useState(false), showCropper = _v[0], setShowCropper = _v[1];
53
+ var _w = useState(initialPreviewUrl || null), previewUrl = _w[0], setPreviewUrl = _w[1];
54
+ var _x = useState(initialCropMetadata || null), cropMetadata = _x[0], setCropMetadata = _x[1];
55
+ var _y = useState(0), internalProgress = _y[0], setInternalProgress = _y[1];
52
56
  var progressIntervalRef = useRef(null);
53
57
  var fileInputRef = useRef(null);
54
- var _x = useState(originalFileName), currentFileName = _x[0], setCurrentFileName = _x[1];
58
+ var _z = useState(originalFileName), currentFileName = _z[0], setCurrentFileName = _z[1];
55
59
  useEffect(function () {
56
60
  if (initialFile) {
57
61
  setSelectedFile(initialFile);
@@ -207,19 +211,153 @@ var FileUploader = function (_a) {
207
211
  setShowCropper(true);
208
212
  }
209
213
  };
214
+ /**
215
+ * Crop l'image côté client et retourne un Blob
216
+ */
217
+ var cropImageToBlob = function (imageUrl, cropMetadata, outputWidth, outputHeight) { return __awaiter(void 0, void 0, void 0, function () {
218
+ return __generator(this, function (_a) {
219
+ return [2 /*return*/, new Promise(function (resolve, reject) {
220
+ var img = new window.Image();
221
+ img.crossOrigin = "anonymous";
222
+ img.onload = function () {
223
+ try {
224
+ // Créer un canvas aux dimensions de sortie
225
+ var canvas = document.createElement("canvas");
226
+ canvas.width = outputWidth;
227
+ canvas.height = outputHeight;
228
+ var ctx = canvas.getContext("2d");
229
+ if (!ctx) {
230
+ reject(new Error("Impossible de créer le contexte canvas"));
231
+ return;
232
+ }
233
+ // Dimensions de la zone de crop (basées sur le modal)
234
+ // On doit retrouver les dimensions de la cropArea du modal
235
+ // Pour simplifier, on considère que la cropArea fait 400x400 pour square
236
+ // et qu'on scale proportionnellement
237
+ var cropAreaWidth = 400;
238
+ var cropAreaHeight = 400;
239
+ if (cropMetadata.shape === "banner") {
240
+ cropAreaWidth = 600;
241
+ cropAreaHeight = 200;
242
+ }
243
+ else if (cropMetadata.shape === "circle") {
244
+ cropAreaWidth = 400;
245
+ cropAreaHeight = 400;
246
+ }
247
+ // Calculer les dimensions de l'image transformée dans le modal
248
+ var scaledImgWidth = img.width * cropMetadata.zoom;
249
+ var scaledImgHeight = img.height * cropMetadata.zoom;
250
+ // Position du coin supérieur gauche de la cropArea par rapport à l'image transformée
251
+ // Dans le modal, l'image est centrée et on a des offsets
252
+ var imgCenterX = scaledImgWidth / 2;
253
+ var imgCenterY = scaledImgHeight / 2;
254
+ // Le centre de la cropArea est au centre du viewport
255
+ // avec les offsets appliqués
256
+ var cropCenterX = imgCenterX - cropMetadata.offsetX;
257
+ var cropCenterY = imgCenterY - cropMetadata.offsetY;
258
+ // Coordonnées du coin supérieur gauche de la zone à cropper
259
+ var sourceX = cropCenterX - cropAreaWidth / 2;
260
+ var sourceY = cropCenterY - cropAreaHeight / 2;
261
+ // Dessiner l'image croppée sur le canvas
262
+ ctx.drawImage(img, sourceX / cropMetadata.zoom, // source x dans l'image originale
263
+ sourceY / cropMetadata.zoom, // source y dans l'image originale
264
+ cropAreaWidth / cropMetadata.zoom, // largeur source
265
+ cropAreaHeight / cropMetadata.zoom, // hauteur source
266
+ 0, 0, outputWidth, outputHeight);
267
+ // Si c'est un cercle, appliquer un masque
268
+ if (cropMetadata.shape === "circle") {
269
+ var imageData = ctx.getImageData(0, 0, outputWidth, outputHeight);
270
+ var pixels = imageData.data;
271
+ var centerX = outputWidth / 2;
272
+ var centerY = outputHeight / 2;
273
+ var radius = outputWidth / 2;
274
+ for (var y = 0; y < outputHeight; y++) {
275
+ for (var x = 0; x < outputWidth; x++) {
276
+ var distance = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2));
277
+ if (distance > radius) {
278
+ var index = (y * outputWidth + x) * 4;
279
+ pixels[index + 3] = 0; // Rendre transparent
280
+ }
281
+ }
282
+ }
283
+ ctx.putImageData(imageData, 0, 0);
284
+ }
285
+ // Convertir en Blob PNG
286
+ canvas.toBlob(function (blob) {
287
+ if (blob) {
288
+ resolve(blob);
289
+ }
290
+ else {
291
+ reject(new Error("Échec de la conversion canvas vers Blob"));
292
+ }
293
+ }, "image/png", 0.95);
294
+ }
295
+ catch (error) {
296
+ reject(error);
297
+ }
298
+ };
299
+ img.onerror = function () {
300
+ reject(new Error("Échec du chargement de l'image"));
301
+ };
302
+ img.src = imageUrl;
303
+ })];
304
+ });
305
+ }); };
210
306
  var handleCropCancel = function () {
211
307
  setShowCropper(false);
212
308
  };
213
- var handleCropConfirm = function (cropMetadata) {
214
- setShowCropper(false);
215
- setCropMetadata(cropMetadata);
216
- if (autoManageProgress) {
217
- startProgressSimulation();
218
- }
219
- if (selectedFile && fileContent) {
220
- onFileRead === null || onFileRead === void 0 ? void 0 : onFileRead(selectedFile, fileContent, cropMetadata);
221
- }
222
- };
309
+ var handleCropConfirm = function (cropMetadata) { return __awaiter(void 0, void 0, void 0, function () {
310
+ var dimensions, croppedBlob, croppedFile, croppedContent, croppedUrl, error_2;
311
+ return __generator(this, function (_a) {
312
+ switch (_a.label) {
313
+ case 0:
314
+ setShowCropper(false);
315
+ setCropMetadata(cropMetadata);
316
+ if (autoManageProgress) {
317
+ startProgressSimulation();
318
+ }
319
+ if (!(selectedFile && fileContent && previewUrl)) return [3 /*break*/, 7];
320
+ if (!clientSideCrop) return [3 /*break*/, 6];
321
+ _a.label = 1;
322
+ case 1:
323
+ _a.trys.push([1, 4, , 5]);
324
+ dimensions = cropOutputDimensions[cropMetadata.shape] ||
325
+ cropOutputDimensions.square ||
326
+ { width: 200, height: 200 };
327
+ return [4 /*yield*/, cropImageToBlob(previewUrl, cropMetadata, dimensions.width, dimensions.height)];
328
+ case 2:
329
+ croppedBlob = _a.sent();
330
+ croppedFile = new File([croppedBlob], selectedFile.name.replace(/\.[^/.]+$/, ".png"), // Remplacer l'extension par .png
331
+ { type: "image/png" });
332
+ return [4 /*yield*/, croppedFile.arrayBuffer()];
333
+ case 3:
334
+ croppedContent = _a.sent();
335
+ croppedUrl = URL.createObjectURL(croppedBlob);
336
+ if (previewUrl && !initialPreviewUrl) {
337
+ URL.revokeObjectURL(previewUrl);
338
+ }
339
+ setPreviewUrl(croppedUrl);
340
+ setSelectedFile(croppedFile);
341
+ setFileContent(croppedContent);
342
+ setCurrentFileName(croppedFile.name);
343
+ // Appeler onFileRead avec le fichier croppé (pas de cropMetadata car déjà croppé)
344
+ onFileRead === null || onFileRead === void 0 ? void 0 : onFileRead(croppedFile, croppedContent);
345
+ return [3 /*break*/, 5];
346
+ case 4:
347
+ error_2 = _a.sent();
348
+ console.error("Erreur lors du crop de l'image:", error_2);
349
+ // En cas d'erreur, fallback sur l'image originale avec métadonnées
350
+ onFileRead === null || onFileRead === void 0 ? void 0 : onFileRead(selectedFile, fileContent, cropMetadata);
351
+ return [3 /*break*/, 5];
352
+ case 5: return [3 /*break*/, 7];
353
+ case 6:
354
+ // Passer l'image originale avec les métadonnées au serveur
355
+ onFileRead === null || onFileRead === void 0 ? void 0 : onFileRead(selectedFile, fileContent, cropMetadata);
356
+ _a.label = 7;
357
+ case 7: return [2 /*return*/];
358
+ }
359
+ });
360
+ }); };
223
361
  var handleFileDelete = function () {
224
362
  if (previewUrl && !initialPreviewUrl) {
225
363
  URL.revokeObjectURL(previewUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allaw-ui",
3
- "version": "5.1.0",
3
+ "version": "5.1.2",
4
4
  "description": "Composants UI pour l'application Allaw",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",