allaw-ui 3.0.2 → 3.0.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.
@@ -23,6 +23,7 @@ export interface FileUploaderProps {
23
23
  maxSizeLabel?: string;
24
24
  fileName?: string;
25
25
  fileSize?: number;
26
+ filePresentationLabel?: string;
26
27
  }
27
28
  declare const FileUploader: React.FC<FileUploaderProps>;
28
29
  export default FileUploader;
@@ -38,12 +38,16 @@ import React, { useState, useRef } from "react";
38
38
  import Image from "next/image";
39
39
  import styles from "./FileUploader.module.css";
40
40
  import ImageCropperModal from "./ImageCropperModal";
41
+ import IconButton from "../../atoms/buttons/IconButton";
42
+ import TertiaryButton from "../../atoms/buttons/TertiaryButton";
41
43
  var FileUploader = function (_a) {
42
- 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.errorMessage, errorMessage = _g === void 0 ? null : _g, _h = _a.buttonLabel, buttonLabel = _h === void 0 ? "Choisir un fichier" : _h, _j = _a.acceptedLabel, acceptedLabel = _j === void 0 ? "Format accepté :" : _j, _k = _a.maxSizeLabel, maxSizeLabel = _k === void 0 ? "Taille maximale :" : _k, fileName = _a.fileName, fileSize = _a.fileSize;
43
- var _l = useState(null), selectedFile = _l[0], setSelectedFile = _l[1];
44
- var _m = useState(null), fileContent = _m[0], setFileContent = _m[1];
45
- var _o = useState(false), isHovering = _o[0], setIsHovering = _o[1];
46
- var _p = useState(false), showCropper = _p[0], setShowCropper = _p[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, 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.errorMessage, errorMessage = _g === void 0 ? null : _g, _h = _a.buttonLabel, buttonLabel = _h === void 0 ? "Choisir un fichier" : _h, _j = _a.acceptedLabel, acceptedLabel = _j === void 0 ? "Format accepté :" : _j, _k = _a.maxSizeLabel, maxSizeLabel = _k === void 0 ? "Taille maximale :" : _k, fileName = _a.fileName, fileSize = _a.fileSize, _l = _a.filePresentationLabel, filePresentationLabel = _l === void 0 ? "Voici votre fichier." : _l;
45
+ var _m = useState(null), selectedFile = _m[0], setSelectedFile = _m[1];
46
+ var _o = useState(null), fileContent = _o[0], setFileContent = _o[1];
47
+ var _p = useState(false), isHovering = _p[0], setIsHovering = _p[1];
48
+ var _q = useState(false), showCropper = _q[0], setShowCropper = _q[1];
49
+ var _r = useState(null), previewUrl = _r[0], setPreviewUrl = _r[1];
50
+ var _s = useState(null), cropMetadata = _s[0], setCropMetadata = _s[1];
47
51
  var fileInputRef = useRef(null);
48
52
  var resetFileInput = function () {
49
53
  if (fileInputRef.current) {
@@ -95,12 +99,14 @@ var FileUploader = function (_a) {
95
99
  });
96
100
  }); };
97
101
  var processFile = function (file) { return __awaiter(void 0, void 0, void 0, function () {
98
- var content, error_1;
102
+ var content, url, error_1;
99
103
  return __generator(this, function (_a) {
100
104
  switch (_a.label) {
101
105
  case 0:
102
106
  if (!validateFile(file)) {
103
107
  setSelectedFile(null);
108
+ setPreviewUrl(null);
109
+ setCropMetadata(null);
104
110
  return [2 /*return*/];
105
111
  }
106
112
  _a.label = 1;
@@ -110,6 +116,24 @@ var FileUploader = function (_a) {
110
116
  case 2:
111
117
  content = _a.sent();
112
118
  setFileContent(content);
119
+ // Créer un aperçu si c'est une image
120
+ if (isImageFile(file)) {
121
+ url = URL.createObjectURL(file);
122
+ setPreviewUrl(url);
123
+ // Si le cadrage n'est pas activé, on utilise une métadonnée par défaut
124
+ if (!enableCropping) {
125
+ setCropMetadata({
126
+ zoom: 1,
127
+ offsetX: 0,
128
+ offsetY: 0,
129
+ shape: cropShape,
130
+ });
131
+ }
132
+ }
133
+ else {
134
+ setPreviewUrl(null);
135
+ setCropMetadata(null);
136
+ }
113
137
  // Si c'est une image et que le cadrage est activé, afficher le composant de cadrage
114
138
  if (enableCropping && isImageFile(file)) {
115
139
  setSelectedFile(file);
@@ -125,28 +149,43 @@ var FileUploader = function (_a) {
125
149
  error_1 = _a.sent();
126
150
  console.error("Error reading file:", error_1);
127
151
  setSelectedFile(null);
152
+ setPreviewUrl(null);
153
+ setCropMetadata(null);
128
154
  return [3 /*break*/, 4];
129
155
  case 4: return [2 /*return*/];
130
156
  }
131
157
  });
132
158
  }); };
159
+ var openCropModal = function () {
160
+ if (selectedFile && isImageFile(selectedFile)) {
161
+ setShowCropper(true);
162
+ }
163
+ };
133
164
  var handleCropCancel = function () {
134
165
  setShowCropper(false);
135
- setSelectedFile(null);
136
- resetFileInput();
137
166
  };
138
167
  var handleCropConfirm = function (cropMetadata) {
139
168
  setShowCropper(false);
169
+ setCropMetadata(cropMetadata);
140
170
  if (selectedFile && fileContent) {
141
171
  onFileRead === null || onFileRead === void 0 ? void 0 : onFileRead(selectedFile, fileContent, cropMetadata);
142
172
  }
143
173
  };
144
174
  var handleFileDelete = function () {
175
+ if (previewUrl) {
176
+ URL.revokeObjectURL(previewUrl);
177
+ }
145
178
  setSelectedFile(null);
146
179
  setFileContent(null);
180
+ setPreviewUrl(null);
181
+ setCropMetadata(null);
147
182
  resetFileInput();
148
183
  onFileRemove === null || onFileRemove === void 0 ? void 0 : onFileRemove();
149
184
  };
185
+ var handleNewFileClick = function () {
186
+ var _a;
187
+ (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
188
+ };
150
189
  var formatFileSize = function (size) {
151
190
  if (size < 1024) {
152
191
  return "".concat(size, " octets");
@@ -160,9 +199,28 @@ var FileUploader = function (_a) {
160
199
  };
161
200
  var displayFileSize = fileSize !== undefined ? fileSize : selectedFile ? selectedFile.size : 0;
162
201
  var displayFileName = fileName || (selectedFile ? selectedFile.name : "");
202
+ var isSelectedImage = selectedFile && isImageFile(selectedFile);
163
203
  return (React.createElement("div", { className: styles.upload_main_container },
164
- enableDragAndDrop ? (React.createElement("div", { className: "".concat(styles.upload_container, " ").concat(isHovering ? styles.drag_over : ""), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } },
165
- React.createElement("div", { className: styles.upload_content },
204
+ enableDragAndDrop ? (React.createElement("div", { className: "".concat(styles.upload_container, " ").concat(isHovering ? styles.drag_over : "", " ").concat(previewUrl ? styles.upload_container_with_preview : ""), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: function () { var _a; return !previewUrl && ((_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click()); } },
205
+ previewUrl ? (React.createElement("div", { className: styles.preview_container, onClick: function (e) {
206
+ var _a;
207
+ // Ne pas déclencher si on clique sur le conteneur d'image
208
+ if (!e.target.closest(".".concat(styles.preview_image_container))) {
209
+ (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
210
+ }
211
+ } },
212
+ React.createElement("div", { className: "".concat(styles.preview_image_container, " ").concat(styles["preview_image_".concat((cropMetadata === null || cropMetadata === void 0 ? void 0 : cropMetadata.shape) || cropShape)]), onClick: function () { return enableCropping && openCropModal(); } },
213
+ React.createElement("div", { className: styles.preview_image_wrapper, style: {
214
+ transform: cropMetadata
215
+ ? "translate(".concat(cropMetadata.offsetX, "px, ").concat(cropMetadata.offsetY, "px) scale(").concat(cropMetadata.zoom, ")")
216
+ : "scale(1)",
217
+ } },
218
+ React.createElement("img", { src: previewUrl, alt: displayFileName, className: styles.preview_image, draggable: false }))),
219
+ enableCropping && (React.createElement("div", { className: styles.edit_button_container, onClick: function (e) {
220
+ e.stopPropagation();
221
+ openCropModal();
222
+ } },
223
+ React.createElement(IconButton, { style: "largeFilled", iconName: "allaw-icon-edit-2" }))))) : (React.createElement("div", { className: styles.upload_content },
166
224
  React.createElement("div", { className: styles.upload_icons },
167
225
  React.createElement("div", { className: styles.upload_file_icon },
168
226
  React.createElement("i", { className: "allaw-icon-file" })),
@@ -173,12 +231,14 @@ var FileUploader = function (_a) {
173
231
  React.createElement("span", null,
174
232
  "Glissez-d\u00E9posez votre fichier, ou",
175
233
  " ",
176
- React.createElement("span", { className: styles.btn_tertiary }, buttonLabel),
177
- React.createElement("input", { id: "file-upload", ref: fileInputRef, type: "file", accept: acceptedExtensions.join(","), style: { display: "none" }, onChange: handleFileSelect })))))) : (React.createElement("div", { className: styles.manual_upload_container },
234
+ React.createElement("span", { className: styles.btn_tertiary }, buttonLabel))))),
235
+ React.createElement("input", { id: "file-upload", ref: fileInputRef, type: "file", accept: acceptedExtensions.join(","), style: { display: "none" }, onChange: handleFileSelect }))) : (React.createElement("div", { className: styles.manual_upload_container },
178
236
  React.createElement("button", { className: styles.file_upload_button, onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } },
179
237
  React.createElement("span", { className: styles.btn_tertiary }, buttonLabel),
180
238
  React.createElement("input", { id: "file-upload", ref: fileInputRef, type: "file", accept: acceptedExtensions.join(","), style: { display: "none" }, onChange: handleFileSelect })))),
181
- React.createElement("div", { className: styles.limits },
239
+ previewUrl ? (React.createElement("div", { className: styles.file_info_container },
240
+ filePresentationLabel && (React.createElement("span", { className: styles.file_presentation_label }, filePresentationLabel)),
241
+ React.createElement(TertiaryButton, { label: "Charger ".concat(isSelectedImage ? "une autre image" : "un autre fichier"), color: "bleu-allaw", variant: true, onClick: handleNewFileClick }))) : (React.createElement("div", { className: styles.limits },
182
242
  React.createElement("div", { className: styles.format },
183
243
  React.createElement("span", { className: styles.limit_text },
184
244
  acceptedLabel,
@@ -189,7 +249,7 @@ var FileUploader = function (_a) {
189
249
  maxSizeLabel,
190
250
  " ",
191
251
  maxFileSizeMB,
192
- " Mo"))),
252
+ " Mo")))),
193
253
  descriptionParts && (React.createElement("p", { className: styles.description },
194
254
  descriptionParts.beforeLink,
195
255
  " ",
@@ -204,7 +264,8 @@ var FileUploader = function (_a) {
204
264
  React.createElement("div", { className: styles.uploaded_file_icon }, iconUrl ? (React.createElement(Image, { src: iconUrl, alt: "File icon", className: styles.file_icon, width: 20, height: 20 })) : (React.createElement("i", { className: "allaw-icon-file" }))),
205
265
  React.createElement("div", { className: styles.uploaded_file_name_size },
206
266
  React.createElement("div", { className: styles.uploaded_file_name },
207
- React.createElement("span", { className: styles.file_name }, displayFileName || "Analyse en cours...")),
267
+ React.createElement("span", { className: styles.file_name }, displayFileName || "Analyse en cours..."),
268
+ selectedFile && (React.createElement("i", { className: "allaw-icon-check ".concat(styles.success_icon) }))),
208
269
  React.createElement("div", { className: styles.uploaded_file_size },
209
270
  React.createElement("span", { className: styles.file_size }, displayFileSize > 0 ? formatFileSize(displayFileSize) : ""))),
210
271
  selectedFile && (React.createElement("div", { className: styles.uploaded_file_delete_container },
@@ -276,6 +276,10 @@
276
276
  font-size: inherit;
277
277
  }
278
278
 
279
+ .format {
280
+ width: 61.8%;
281
+ }
282
+
279
283
  @media (max-width: 768px) {
280
284
  .upload_container {
281
285
  padding: 2rem 1rem;
@@ -296,4 +300,116 @@
296
300
  align-items: flex-start;
297
301
  gap: 0.25rem;
298
302
  }
303
+
304
+ .format {
305
+ width: 100%;
306
+ }
307
+ }
308
+
309
+ .upload_container_with_preview {
310
+ padding: 0;
311
+ cursor: default;
312
+ }
313
+
314
+ .preview_container {
315
+ width: 100%;
316
+ height: 300px;
317
+ position: relative;
318
+ display: flex;
319
+ justify-content: center;
320
+ align-items: center;
321
+ background-color: rgba(0, 0, 0, 0.03);
322
+ overflow: hidden;
323
+ cursor: pointer;
324
+ }
325
+
326
+ .preview_image_container {
327
+ position: relative;
328
+ width: 280px;
329
+ height: 280px;
330
+ display: flex;
331
+ justify-content: center;
332
+ align-items: center;
333
+ overflow: hidden;
334
+ }
335
+
336
+ .preview_image_circle {
337
+ border-radius: 50%;
338
+ }
339
+
340
+ .preview_image_square {
341
+ border-radius: 8px;
342
+ }
343
+
344
+ .preview_image_wrapper {
345
+ position: absolute;
346
+ width: auto;
347
+ height: auto;
348
+ max-width: none;
349
+ max-height: none;
350
+ transform-origin: center;
351
+ display: flex;
352
+ justify-content: center;
353
+ align-items: center;
354
+ will-change: transform;
355
+ pointer-events: none;
356
+ }
357
+
358
+ .preview_image {
359
+ width: auto;
360
+ height: auto;
361
+ object-fit: cover;
362
+ display: block;
363
+ max-width: none;
364
+ max-height: none;
365
+ user-select: none;
366
+ -webkit-user-drag: none;
367
+ }
368
+
369
+ .edit_button_container {
370
+ position: absolute;
371
+ bottom: 12px;
372
+ right: 12px;
373
+ z-index: 20;
374
+ pointer-events: auto;
375
+ }
376
+
377
+ .edit_button_container button {
378
+ pointer-events: auto;
379
+ }
380
+
381
+ .file_info_container {
382
+ display: flex;
383
+ align-items: center;
384
+ justify-content: center;
385
+ margin-top: 12px;
386
+ flex-wrap: wrap;
387
+ gap: 8px;
388
+ }
389
+
390
+ .file_info_container span {
391
+ font-family: var(--font-open-sans, sans-serif);
392
+ font-size: 14px;
393
+ color: var(----noir, #171e25);
394
+ }
395
+
396
+ .file_presentation_label {
397
+ font-size: 14px;
398
+ color: var(--gris-03);
399
+ }
400
+
401
+ .change_file_link {
402
+ cursor: pointer;
403
+ text-decoration: none;
404
+ }
405
+
406
+ .success_icon {
407
+ margin-left: 8px;
408
+ color: var(--actions-valid, #29a36a);
409
+ font-size: 14px;
410
+ }
411
+
412
+ .uploaded_file_name {
413
+ display: flex;
414
+ align-items: center;
299
415
  }
@@ -103,4 +103,5 @@ export const WithProgress: any;
103
103
  export const MultipleExtensions: any;
104
104
  export const WithSquareCropping: any;
105
105
  export const WithCircleCropping: any;
106
+ export const WithPreloadedImage: any;
106
107
  import FileUploader from "./FileUploader";
@@ -183,6 +183,7 @@ Default.args = {
183
183
  buttonLabel: "Choisir une image",
184
184
  acceptedLabel: "Formats acceptés :",
185
185
  maxSizeLabel: "Taille maximale :",
186
+ filePresentationLabel: "Voici votre logo.",
186
187
  };
187
188
  export var WithDescription = Template.bind({});
188
189
  WithDescription.args = __assign(__assign({}, Default.args), { descriptionParts: {
@@ -224,3 +225,8 @@ WithCircleCropping.args = {
224
225
  acceptedLabel: "Formats acceptés :",
225
226
  maxSizeLabel: "Taille maximale :",
226
227
  };
228
+ // Exemple avec l'affichage d'une image préuploadée
229
+ export var WithPreloadedImage = Template.bind({});
230
+ WithPreloadedImage.args = __assign(__assign({}, Default.args), {
231
+ // On simule un fichier déjà chargé pour la story
232
+ fileName: "logo-entreprise.png", fileSize: 1.2 * 1024 * 1024, filePresentationLabel: "Voici votre logo." });
@@ -200,8 +200,9 @@ var ImageCropperModal = function (_a) {
200
200
  React.createElement("div", { className: styles.action_buttons },
201
201
  React.createElement("button", { className: styles.cancel_button, onClick: onCancel }, "Annuler"),
202
202
  React.createElement("button", { className: styles.confirm_button, onClick: function () {
203
- return onConfirm({
204
- zoom: zoom,
203
+ // Retourner les métadonnées de cadrage avec le zoom total
204
+ onConfirm({
205
+ zoom: baseZoom * zoom,
205
206
  offsetX: position.x,
206
207
  offsetY: position.y,
207
208
  shape: shape,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allaw-ui",
3
- "version": "3.0.2",
3
+ "version": "3.0.4",
4
4
  "description": "Composants UI pour l'application Allaw",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",