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.
- package/dist/components/molecules/fileUploader/FileUploader.d.ts +1 -0
- package/dist/components/molecules/fileUploader/FileUploader.js +76 -15
- package/dist/components/molecules/fileUploader/FileUploader.module.css +116 -0
- package/dist/components/molecules/fileUploader/FileUploader.stories.d.ts +1 -0
- package/dist/components/molecules/fileUploader/FileUploader.stories.js +6 -0
- package/dist/components/molecules/fileUploader/ImageCropperModal.js +3 -2
- package/package.json +1 -1
|
@@ -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
|
|
44
|
-
var
|
|
45
|
-
var
|
|
46
|
-
var
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
}
|
|
@@ -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
|
-
|
|
204
|
-
|
|
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,
|