easy-file-dragdrop 1.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/index.js ADDED
@@ -0,0 +1,491 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ InputCanvas: () => InputCanvas,
34
+ useDragDrop: () => useDragdrop,
35
+ useDragdrop: () => useDragdrop
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/components/InputCanvas.tsx
40
+ var import_image = __toESM(require("next/image"));
41
+ var import_fi = require("react-icons/fi");
42
+
43
+ // src/components/useDragdrop.ts
44
+ var import_react = require("react");
45
+ var bytesPerKilobyte = 1024;
46
+ function toBase64(file) {
47
+ return new Promise((resolve, reject) => {
48
+ const reader = new FileReader();
49
+ reader.onload = () => resolve(String(reader.result ?? ""));
50
+ reader.onerror = () => reject(new Error("Could not convert file to base64"));
51
+ reader.readAsDataURL(file);
52
+ });
53
+ }
54
+ function createFileId(file) {
55
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
56
+ return crypto.randomUUID();
57
+ }
58
+ return `${file.name}-${file.lastModified}-${Math.random().toString(36).slice(2)}`;
59
+ }
60
+ function createFileKey(file) {
61
+ return `${file.name}-${file.size}-${file.lastModified}-${file.type}`;
62
+ }
63
+ function doesFileMatchAccept(file, accept) {
64
+ if (!accept || accept.trim().length === 0) {
65
+ return true;
66
+ }
67
+ const acceptedTokens = accept.split(",").map((token) => token.trim().toLowerCase());
68
+ const fileName = file.name.toLowerCase();
69
+ const fileType = file.type.toLowerCase();
70
+ return acceptedTokens.some((token) => {
71
+ if (!token) {
72
+ return false;
73
+ }
74
+ if (token.startsWith(".")) {
75
+ return fileName.endsWith(token);
76
+ }
77
+ if (token.endsWith("/*")) {
78
+ const rootType = token.slice(0, token.length - 1);
79
+ return fileType.startsWith(rootType);
80
+ }
81
+ return fileType === token;
82
+ });
83
+ }
84
+ function useDragdrop(options = {}) {
85
+ const {
86
+ accept,
87
+ maxFiles,
88
+ maxFileSize,
89
+ multiple = true,
90
+ validation,
91
+ value,
92
+ onChange,
93
+ onFileAdd,
94
+ onFileAddB24,
95
+ onFileRemove,
96
+ showPreview = true,
97
+ disabled = false
98
+ } = options;
99
+ const [files, setFiles] = (0, import_react.useState)([]);
100
+ const [dragActive, setDragActive] = (0, import_react.useState)(false);
101
+ const [error, setError] = (0, import_react.useState)(null);
102
+ const inputRef = (0, import_react.useRef)(null);
103
+ const emitFilesChange = (0, import_react.useCallback)((nextFiles) => {
104
+ const flatFiles = nextFiles.map((item) => item.file);
105
+ if (onChange) {
106
+ onChange(flatFiles);
107
+ }
108
+ }, [onChange]);
109
+ (0, import_react.useEffect)(() => {
110
+ if (!value) {
111
+ return;
112
+ }
113
+ setFiles((previous) => {
114
+ const previousByKey = new Map(previous.map((item) => [createFileKey(item.file), item]));
115
+ const next = value.map((file) => {
116
+ const key = createFileKey(file);
117
+ const existing = previousByKey.get(key);
118
+ if (existing) {
119
+ return existing;
120
+ }
121
+ const isImage = file.type.startsWith("image/");
122
+ return {
123
+ id: createFileId(file),
124
+ file,
125
+ isImage,
126
+ previewUrl: showPreview && isImage ? URL.createObjectURL(file) : void 0
127
+ };
128
+ });
129
+ const nextIds = new Set(next.map((item) => item.id));
130
+ previous.forEach((item) => {
131
+ if (!nextIds.has(item.id) && item.previewUrl) {
132
+ URL.revokeObjectURL(item.previewUrl);
133
+ }
134
+ });
135
+ return next;
136
+ });
137
+ }, [showPreview, value]);
138
+ const maxSizeInBytes = (0, import_react.useMemo)(() => {
139
+ if (!maxFileSize || maxFileSize <= 0) {
140
+ return void 0;
141
+ }
142
+ return maxFileSize * bytesPerKilobyte * bytesPerKilobyte;
143
+ }, [maxFileSize]);
144
+ const addFiles = (0, import_react.useCallback)(async (incoming) => {
145
+ if (disabled) {
146
+ return;
147
+ }
148
+ setError(null);
149
+ const inputFiles = Array.from(incoming);
150
+ if (inputFiles.length === 0) {
151
+ return;
152
+ }
153
+ const selectedFiles = multiple ? inputFiles : inputFiles.slice(0, 1);
154
+ const nextFiles = [];
155
+ const fileErrors = [];
156
+ for (const file of selectedFiles) {
157
+ if (!doesFileMatchAccept(file, accept)) {
158
+ fileErrors.push(`File type not accepted: ${file.name}`);
159
+ continue;
160
+ }
161
+ if (maxSizeInBytes && file.size > maxSizeInBytes) {
162
+ fileErrors.push(`File too large: ${file.name}`);
163
+ continue;
164
+ }
165
+ if (validation && !validation(file)) {
166
+ fileErrors.push(`Validation failed: ${file.name}`);
167
+ continue;
168
+ }
169
+ const isImage = file.type.startsWith("image/");
170
+ nextFiles.push({
171
+ id: createFileId(file),
172
+ file,
173
+ isImage,
174
+ previewUrl: showPreview && isImage ? URL.createObjectURL(file) : void 0
175
+ });
176
+ }
177
+ if (fileErrors.length > 0) {
178
+ setError(fileErrors[0]);
179
+ }
180
+ if (nextFiles.length === 0) {
181
+ return;
182
+ }
183
+ let removedByLimit = [];
184
+ let updatedFiles = [];
185
+ setFiles((previous) => {
186
+ const merged = multiple ? [...previous, ...nextFiles] : [nextFiles[0]];
187
+ if (!maxFiles || maxFiles <= 0) {
188
+ updatedFiles = merged;
189
+ return merged;
190
+ }
191
+ if (merged.length <= maxFiles) {
192
+ updatedFiles = merged;
193
+ return merged;
194
+ }
195
+ setError(`Maximum ${maxFiles} file${maxFiles > 1 ? "s" : ""} allowed`);
196
+ removedByLimit = merged.slice(maxFiles);
197
+ const limited = merged.slice(0, maxFiles);
198
+ updatedFiles = limited;
199
+ return limited;
200
+ });
201
+ if (removedByLimit.length > 0) {
202
+ removedByLimit.forEach((item) => {
203
+ if (item.previewUrl) {
204
+ URL.revokeObjectURL(item.previewUrl);
205
+ }
206
+ });
207
+ }
208
+ if (onFileAdd || onFileAddB24) {
209
+ for (const item of nextFiles) {
210
+ if (onFileAdd) {
211
+ onFileAdd(item.file);
212
+ }
213
+ if (onFileAddB24) {
214
+ const base64 = await toBase64(item.file);
215
+ onFileAddB24(base64);
216
+ }
217
+ }
218
+ }
219
+ emitFilesChange(updatedFiles);
220
+ if (inputRef.current) {
221
+ inputRef.current.value = "";
222
+ }
223
+ }, [accept, disabled, emitFilesChange, maxFiles, maxSizeInBytes, multiple, onFileAdd, onFileAddB24, showPreview, validation]);
224
+ const removeFile = (0, import_react.useCallback)((id) => {
225
+ let removedFile;
226
+ let updatedFiles = [];
227
+ setFiles((previous) => {
228
+ removedFile = previous.find((item) => item.id === id);
229
+ const next = previous.filter((item) => item.id !== id);
230
+ updatedFiles = next;
231
+ return next;
232
+ });
233
+ if (removedFile?.previewUrl) {
234
+ URL.revokeObjectURL(removedFile.previewUrl);
235
+ }
236
+ if (removedFile?.file && onFileRemove) {
237
+ onFileRemove(removedFile.file);
238
+ }
239
+ emitFilesChange(updatedFiles);
240
+ }, [emitFilesChange, onFileRemove]);
241
+ const clearFiles = (0, import_react.useCallback)(() => {
242
+ setFiles((previous) => {
243
+ previous.forEach((item) => {
244
+ if (item.previewUrl) {
245
+ URL.revokeObjectURL(item.previewUrl);
246
+ }
247
+ });
248
+ return [];
249
+ });
250
+ emitFilesChange([]);
251
+ }, [emitFilesChange]);
252
+ (0, import_react.useEffect)(() => {
253
+ return () => {
254
+ files.forEach((item) => {
255
+ if (item.previewUrl) {
256
+ URL.revokeObjectURL(item.previewUrl);
257
+ }
258
+ });
259
+ };
260
+ }, [files]);
261
+ const onDragEnter = (0, import_react.useCallback)((event) => {
262
+ event.preventDefault();
263
+ event.stopPropagation();
264
+ if (!disabled) {
265
+ setDragActive(true);
266
+ }
267
+ }, [disabled]);
268
+ const onDragOver = (0, import_react.useCallback)((event) => {
269
+ event.preventDefault();
270
+ event.stopPropagation();
271
+ if (!disabled) {
272
+ setDragActive(true);
273
+ }
274
+ }, [disabled]);
275
+ const onDragLeave = (0, import_react.useCallback)((event) => {
276
+ event.preventDefault();
277
+ event.stopPropagation();
278
+ setDragActive(false);
279
+ }, []);
280
+ const onDrop = (0, import_react.useCallback)(async (event) => {
281
+ event.preventDefault();
282
+ event.stopPropagation();
283
+ setDragActive(false);
284
+ if (disabled) {
285
+ return;
286
+ }
287
+ await addFiles(event.dataTransfer.files);
288
+ }, [addFiles, disabled]);
289
+ const onInputChange = (0, import_react.useCallback)(async (event) => {
290
+ const selected = event.target.files;
291
+ if (!selected || disabled) {
292
+ return;
293
+ }
294
+ await addFiles(selected);
295
+ }, [addFiles, disabled]);
296
+ const openFileDialog = (0, import_react.useCallback)(() => {
297
+ if (!disabled) {
298
+ inputRef.current?.click();
299
+ }
300
+ }, [disabled]);
301
+ return {
302
+ files,
303
+ dragActive,
304
+ error,
305
+ inputRef,
306
+ addFiles,
307
+ removeFile,
308
+ clearFiles,
309
+ openFileDialog,
310
+ onDragEnter,
311
+ onDragOver,
312
+ onDragLeave,
313
+ onDrop,
314
+ onInputChange
315
+ };
316
+ }
317
+
318
+ // src/components/InputCanvas.tsx
319
+ var import_jsx_runtime = require("react/jsx-runtime");
320
+ function cn(...values) {
321
+ return values.filter(Boolean).join(" ");
322
+ }
323
+ function formatFileSize(sizeInBytes) {
324
+ if (sizeInBytes === 0) {
325
+ return "0 B";
326
+ }
327
+ const units = ["B", "KB", "MB", "GB"];
328
+ const sizeLevel = Math.min(Math.floor(Math.log(sizeInBytes) / Math.log(1024)), units.length - 1);
329
+ const size = sizeInBytes / Math.pow(1024, sizeLevel);
330
+ return `${size.toFixed(size >= 10 || sizeLevel === 0 ? 0 : 1)} ${units[sizeLevel]}`;
331
+ }
332
+ function getFileTypeIcon(file) {
333
+ const fileType = file.type.toLowerCase();
334
+ const fileName = file.name.toLowerCase();
335
+ if (fileType.startsWith("image/")) {
336
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiImage, { size: 22 });
337
+ }
338
+ if (fileType.startsWith("video/")) {
339
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiFilm, { size: 22 });
340
+ }
341
+ if (fileType.startsWith("audio/")) {
342
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiMusic, { size: 22 });
343
+ }
344
+ if (fileType.includes("pdf") || fileName.endsWith(".pdf")) {
345
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiFileText, { size: 22 });
346
+ }
347
+ if (fileType.includes("zip") || fileType.includes("compressed") || /\.(zip|rar|7z|tar|gz)$/.test(fileName)) {
348
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiPackage, { size: 22 });
349
+ }
350
+ if (fileType.includes("json") || fileType.includes("javascript") || fileType.includes("typescript") || /\.(js|jsx|ts|tsx|json|xml|yml|yaml)$/.test(fileName)) {
351
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiCode, { size: 22 });
352
+ }
353
+ if (fileType.startsWith("text/") || fileType.includes("msword") || fileType.includes("officedocument") || /\.(txt|md|csv|doc|docx|xls|xlsx|ppt|pptx)$/.test(fileName)) {
354
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiFileText, { size: 22 });
355
+ }
356
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiFile, { size: 22 });
357
+ }
358
+ function InputCanvas(props) {
359
+ const {
360
+ name,
361
+ label = "Upload files",
362
+ description,
363
+ error: externalError,
364
+ accept,
365
+ multiple = false,
366
+ disabled = false,
367
+ onBlur,
368
+ className,
369
+ classNames,
370
+ dropzoneText = "Drag and drop files here",
371
+ dropzoneActiveText = "Drop files to upload",
372
+ browseText = "Browse",
373
+ removeButtonLabel = "Remove",
374
+ showPreview = true
375
+ } = props;
376
+ const {
377
+ files,
378
+ dragActive,
379
+ error: internalError,
380
+ inputRef,
381
+ removeFile,
382
+ openFileDialog,
383
+ onDragEnter,
384
+ onDragOver,
385
+ onDragLeave,
386
+ onDrop,
387
+ onInputChange
388
+ } = useDragdrop(props);
389
+ const shouldShowDropzone = multiple || files.length === 0;
390
+ const disabledClass = "efd-dropzone--disabled";
391
+ const error = internalError || externalError;
392
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("efd-root", className, classNames?.root), children: [
393
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "efd-header", children: [
394
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: cn("efd-label", classNames?.label), children: label }),
395
+ description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: cn("efd-description", classNames?.description), children: description }) : null
396
+ ] }),
397
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
398
+ "input",
399
+ {
400
+ ref: inputRef,
401
+ name,
402
+ type: "file",
403
+ className: "efd-hidden-input",
404
+ accept,
405
+ multiple,
406
+ disabled,
407
+ onBlur,
408
+ onChange: onInputChange
409
+ }
410
+ ),
411
+ shouldShowDropzone ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
412
+ "div",
413
+ {
414
+ className: cn(
415
+ "efd-dropzone",
416
+ !disabled && "efd-dropzone--interactive",
417
+ dragActive && "efd-dropzone--active",
418
+ disabled && disabledClass,
419
+ classNames?.dropzone,
420
+ dragActive && classNames?.dropzoneActive,
421
+ disabled && classNames?.dropzoneDisabled
422
+ ),
423
+ role: "button",
424
+ tabIndex: disabled ? -1 : 0,
425
+ onClick: openFileDialog,
426
+ onDragEnter,
427
+ onDragOver,
428
+ onDragLeave,
429
+ onDrop,
430
+ onKeyDown: (event) => {
431
+ if (event.key === "Enter" || event.key === " ") {
432
+ event.preventDefault();
433
+ openFileDialog();
434
+ }
435
+ },
436
+ "aria-disabled": disabled,
437
+ children: [
438
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("efd-upload-icon"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiUploadCloud, { size: 28 }) }),
439
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: cn("efd-helper-text", classNames?.helperText), children: [
440
+ dragActive ? dropzoneActiveText : dropzoneText,
441
+ " ",
442
+ " ",
443
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn("efd-browse-text"), children: browseText })
444
+ ] })
445
+ ]
446
+ }
447
+ ) : null,
448
+ error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: cn("efd-error", classNames?.errorText), children: externalError }) : null,
449
+ !!files.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cn("efd-file-list", classNames?.fileList), children: files.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
450
+ "li",
451
+ {
452
+ className: cn("efd-file-item", classNames?.fileItem),
453
+ children: [
454
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("efd-preview", classNames?.preview), children: showPreview && item.isImage && item.previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
455
+ import_image.default,
456
+ {
457
+ src: item.previewUrl,
458
+ alt: item.file.name,
459
+ width: 80,
460
+ height: 80,
461
+ unoptimized: true,
462
+ className: "efd-preview-image"
463
+ }
464
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "efd-preview-icon", children: getFileTypeIcon(item.file) }) }),
465
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("efd-file-meta", classNames?.fileMeta), children: [
466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: cn("efd-file-name", classNames?.fileName), children: item.file.name }),
467
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: cn("efd-file-size", classNames?.fileSize), children: formatFileSize(item.file.size) })
468
+ ] }),
469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
470
+ "button",
471
+ {
472
+ type: "button",
473
+ onClick: () => removeFile(item.id),
474
+ className: cn("efd-remove-button", classNames?.removeButton),
475
+ "aria-label": `${removeButtonLabel} ${item.file.name}`,
476
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fi.FiX, { size: 16 })
477
+ }
478
+ )
479
+ ]
480
+ },
481
+ item.id
482
+ )) })
483
+ ] });
484
+ }
485
+ // Annotate the CommonJS export names for ESM import in node:
486
+ 0 && (module.exports = {
487
+ InputCanvas,
488
+ useDragDrop,
489
+ useDragdrop
490
+ });
491
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/components/InputCanvas.tsx","../src/components/useDragdrop.ts"],"sourcesContent":["export { default as InputCanvas } from \"./components/InputCanvas\";\r\nexport { default as useDragdrop } from \"./components/useDragdrop\";\r\nexport { default as useDragDrop } from \"./components/useDragdrop\";\r\nexport type {\r\n\tDragDropClassNames,\r\n\tDragDropFileItem,\r\n\tSimpleDragDropParams\r\n} from \"./types\";\r\n","\"use client\";\r\n\r\nimport \"./InputCanvas.css\";\r\nimport Image from \"next/image\";\r\nimport {\r\n\tFiCode,\r\n\tFiFile,\r\n\tFiFileText,\r\n\tFiFilm,\r\n\tFiImage,\r\n\tFiMusic,\r\n\tFiPackage,\r\n\tFiUploadCloud,\r\n\tFiX\r\n} from \"react-icons/fi\";\r\nimport useDragdrop from \"./useDragdrop\";\r\nimport { SimpleDragDropParams } from \"../types\";\r\n\r\nfunction cn(...values: Array<string | undefined | false | null>): string {\r\n\treturn values.filter(Boolean).join(\" \");\r\n}\r\n\r\nfunction formatFileSize(sizeInBytes: number): string {\r\n\tif (sizeInBytes === 0) {\r\n\t\treturn \"0 B\";\r\n\t}\r\n\r\n\tconst units = [\"B\", \"KB\", \"MB\", \"GB\"];\r\n\tconst sizeLevel = Math.min(Math.floor(Math.log(sizeInBytes) / Math.log(1024)), units.length - 1);\r\n\tconst size = sizeInBytes / Math.pow(1024, sizeLevel);\r\n\treturn `${size.toFixed(size >= 10 || sizeLevel === 0 ? 0 : 1)} ${units[sizeLevel]}`;\r\n}\r\n\r\nfunction getFileTypeIcon(file: File): React.ReactNode {\r\n\tconst fileType = file.type.toLowerCase();\r\n\tconst fileName = file.name.toLowerCase();\r\n\r\n\tif (fileType.startsWith(\"image/\")) {\r\n\t\treturn <FiImage size={22} />;\r\n\t}\r\n\r\n\tif (fileType.startsWith(\"video/\")) {\r\n\t\treturn <FiFilm size={22} />;\r\n\t}\r\n\r\n\tif (fileType.startsWith(\"audio/\")) {\r\n\t\treturn <FiMusic size={22} />;\r\n\t}\r\n\r\n\tif (fileType.includes(\"pdf\") || fileName.endsWith(\".pdf\")) {\r\n\t\treturn <FiFileText size={22} />;\r\n\t}\r\n\r\n\tif (fileType.includes(\"zip\") || fileType.includes(\"compressed\") || /\\.(zip|rar|7z|tar|gz)$/.test(fileName)) {\r\n\t\treturn <FiPackage size={22} />;\r\n\t}\r\n\r\n\tif (fileType.includes(\"json\") || fileType.includes(\"javascript\") || fileType.includes(\"typescript\") || /\\.(js|jsx|ts|tsx|json|xml|yml|yaml)$/.test(fileName)) {\r\n\t\treturn <FiCode size={22} />;\r\n\t}\r\n\r\n\tif (\r\n\t\tfileType.startsWith(\"text/\") ||\r\n\t\tfileType.includes(\"msword\") ||\r\n\t\tfileType.includes(\"officedocument\") ||\r\n\t\t/\\.(txt|md|csv|doc|docx|xls|xlsx|ppt|pptx)$/.test(fileName)\r\n\t) {\r\n\t\treturn <FiFileText size={22} />;\r\n\t}\r\n\r\n\treturn <FiFile size={22} />;\r\n}\r\n\r\nexport default function InputCanvas(props: SimpleDragDropParams) {\r\n\tconst {\r\n\t\tname,\r\n\t\tlabel = \"Upload files\",\r\n\t\tdescription,\r\n\t\terror: externalError,\r\n\t\taccept,\r\n\t\tmultiple = false,\r\n\t\tdisabled = false,\r\n\t\tonBlur,\r\n\t\tclassName,\r\n\t\tclassNames,\r\n\t\tdropzoneText = \"Drag and drop files here\",\r\n\t\tdropzoneActiveText = \"Drop files to upload\",\r\n\t\tbrowseText = \"Browse\",\r\n\t\tremoveButtonLabel = \"Remove\",\r\n\t\tshowPreview = true\r\n\t} = props;\r\n\r\n\tconst {\r\n\t\tfiles,\r\n\t\tdragActive,\r\n\t\terror: internalError,\r\n\t\tinputRef,\r\n\t\tremoveFile,\r\n\t\topenFileDialog,\r\n\t\tonDragEnter,\r\n\t\tonDragOver,\r\n\t\tonDragLeave,\r\n\t\tonDrop,\r\n\t\tonInputChange\r\n\t} = useDragdrop(props);\r\n\r\n\tconst shouldShowDropzone = multiple || files.length === 0;\r\n\tconst disabledClass = \"efd-dropzone--disabled\";\r\n\tconst error = internalError || externalError;\r\n\r\n\treturn (\r\n\t\t<div className={cn(\"efd-root\", className, classNames?.root)}>\r\n\t\t\t<div className=\"efd-header\">\r\n\t\t\t\t<label className={cn(\"efd-label\", classNames?.label)}>\r\n\t\t\t\t\t{label}\r\n\t\t\t\t</label>\r\n\t\t\t\t{description ? (\r\n\t\t\t\t\t<p className={cn(\"efd-description\", classNames?.description)}>{description}</p>\r\n\t\t\t\t) : null}\r\n\t\t\t</div>\r\n\r\n\t\t\t<input\r\n\t\t\t\tref={inputRef}\r\n\t\t\t\tname={name}\r\n\t\t\t\ttype=\"file\"\r\n\t\t\t\tclassName=\"efd-hidden-input\"\r\n\t\t\t\taccept={accept}\r\n\t\t\t\tmultiple={multiple}\r\n\t\t\t\tdisabled={disabled}\r\n\t\t\t\tonBlur={onBlur}\r\n\t\t\t\tonChange={onInputChange}\r\n\t\t\t/>\r\n\r\n\t\t\t{shouldShowDropzone ? (\r\n\t\t\t\t<div\r\n\t\t\t\t\tclassName={cn(\r\n\t\t\t\t\t\t\"efd-dropzone\",\r\n\t\t\t\t\t\t!disabled && \"efd-dropzone--interactive\",\r\n\t\t\t\t\t\tdragActive && \"efd-dropzone--active\",\r\n\t\t\t\t\t\tdisabled && disabledClass,\r\n\t\t\t\t\t\tclassNames?.dropzone,\r\n\t\t\t\t\t\tdragActive && classNames?.dropzoneActive,\r\n\t\t\t\t\t\tdisabled && classNames?.dropzoneDisabled\r\n\t\t\t\t\t)}\r\n\t\t\t\t\trole=\"button\"\r\n\t\t\t\t\ttabIndex={disabled ? -1 : 0}\r\n\t\t\t\t\tonClick={openFileDialog}\r\n\t\t\t\t\tonDragEnter={onDragEnter}\r\n\t\t\t\t\tonDragOver={onDragOver}\r\n\t\t\t\t\tonDragLeave={onDragLeave}\r\n\t\t\t\t\tonDrop={onDrop}\r\n\t\t\t\t\tonKeyDown={(event) => {\r\n\t\t\t\t\t\tif (event.key === \"Enter\" || event.key === \" \") {\r\n\t\t\t\t\t\t\tevent.preventDefault();\r\n\t\t\t\t\t\t\topenFileDialog();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t\taria-disabled={disabled}\r\n\t\t\t\t>\r\n\t\t\t\t\t<div className={cn(\"efd-upload-icon\")}> \r\n\t\t\t\t\t\t<FiUploadCloud size={28} />\r\n\t\t\t\t\t</div>\r\n\r\n\t\t\t\t\t<p className={cn(\"efd-helper-text\", classNames?.helperText)}>\r\n\t\t\t\t\t\t{dragActive ? dropzoneActiveText : dropzoneText} {\" \"}\r\n\t\t\t\t\t\t<span className={cn(\"efd-browse-text\")}>{browseText}</span>\r\n\t\t\t\t\t</p>\r\n\t\t\t\t</div>\r\n\t\t\t) : null}\r\n\r\n\t\t\t{error ? (\r\n\t\t\t\t<p className={cn(\"efd-error\", classNames?.errorText)}>{externalError}</p>\r\n\t\t\t) : null}\r\n\r\n\t\t\t{!!files.length && (\r\n\t\t\t\t<ul className={cn(\"efd-file-list\", classNames?.fileList)}>\r\n\t\t\t\t\t{files.map((item) => (\r\n\t\t\t\t\t\t<li\r\n\t\t\t\t\t\t\tkey={item.id}\r\n\t\t\t\t\t\t\tclassName={cn(\"efd-file-item\", classNames?.fileItem)}\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t<div className={cn(\"efd-preview\", classNames?.preview)}>\r\n\t\t\t\t\t\t\t\t{showPreview && item.isImage && item.previewUrl ? (\r\n\t\t\t\t\t\t\t\t\t<Image\r\n\t\t\t\t\t\t\t\t\t\tsrc={item.previewUrl}\r\n\t\t\t\t\t\t\t\t\t\talt={item.file.name}\r\n\t\t\t\t\t\t\t\t\t\twidth={80}\r\n\t\t\t\t\t\t\t\t\t\theight={80}\r\n\t\t\t\t\t\t\t\t\t\tunoptimized\r\n\t\t\t\t\t\t\t\t\t\tclassName=\"efd-preview-image\"\r\n\t\t\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\t\t\t<div className=\"efd-preview-icon\">\r\n\t\t\t\t\t\t\t\t\t\t{getFileTypeIcon(item.file)}\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t</div>\r\n\r\n\t\t\t\t\t\t\t<div className={cn(\"efd-file-meta\", classNames?.fileMeta)}>\r\n\t\t\t\t\t\t\t\t<p className={cn(\"efd-file-name\", classNames?.fileName)}>\r\n\t\t\t\t\t\t\t\t\t{item.file.name}\r\n\t\t\t\t\t\t\t\t</p>\r\n\t\t\t\t\t\t\t\t<p className={cn(\"efd-file-size\", classNames?.fileSize)}>\r\n\t\t\t\t\t\t\t\t\t{formatFileSize(item.file.size)}\r\n\t\t\t\t\t\t\t\t</p>\r\n\t\t\t\t\t\t\t</div>\r\n\r\n\t\t\t\t\t\t\t<button\r\n\t\t\t\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t\t\t\tonClick={() => removeFile(item.id)}\r\n\t\t\t\t\t\t\t\tclassName={cn(\"efd-remove-button\", classNames?.removeButton)}\r\n\t\t\t\t\t\t\t\taria-label={`${removeButtonLabel} ${item.file.name}`}\r\n\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t<FiX size={16} />\r\n\t\t\t\t\t\t\t</button>\r\n\t\t\t\t\t\t</li>\r\n\t\t\t\t\t))}\r\n\t\t\t\t</ul>\r\n\t\t\t)}\r\n\t\t</div>\r\n\t);\r\n}","\"use client\";\r\n\r\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\r\nimport { DragDropFileItem, SimpleDragDropParams } from \"../types\";\r\n\r\ninterface UseDragDropResult {\r\n files: DragDropFileItem[];\r\n dragActive: boolean;\r\n error: string | null;\r\n inputRef: React.RefObject<HTMLInputElement | null>;\r\n addFiles: (incoming: FileList | File[]) => Promise<void>;\r\n removeFile: (id: string) => void;\r\n clearFiles: () => void;\r\n openFileDialog: () => void;\r\n onDragEnter: (event: React.DragEvent<HTMLElement>) => void;\r\n onDragOver: (event: React.DragEvent<HTMLElement>) => void;\r\n onDragLeave: (event: React.DragEvent<HTMLElement>) => void;\r\n onDrop: (event: React.DragEvent<HTMLElement>) => Promise<void>;\r\n onInputChange: (event: React.ChangeEvent<HTMLInputElement>) => Promise<void>;\r\n}\r\n\r\nconst bytesPerKilobyte = 1024;\r\n\r\nfunction toBase64(file: File): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const reader = new FileReader();\r\n reader.onload = () => resolve(String(reader.result ?? \"\"));\r\n reader.onerror = () => reject(new Error(\"Could not convert file to base64\"));\r\n reader.readAsDataURL(file);\r\n });\r\n}\r\n\r\nfunction createFileId(file: File): string {\r\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\r\n return crypto.randomUUID();\r\n }\r\n\r\n return `${file.name}-${file.lastModified}-${Math.random().toString(36).slice(2)}`;\r\n}\r\n\r\nfunction createFileKey(file: File): string {\r\n return `${file.name}-${file.size}-${file.lastModified}-${file.type}`;\r\n}\r\n\r\nfunction doesFileMatchAccept(file: File, accept?: string): boolean {\r\n if (!accept || accept.trim().length === 0) {\r\n return true;\r\n }\r\n\r\n const acceptedTokens = accept.split(\",\").map((token) => token.trim().toLowerCase());\r\n const fileName = file.name.toLowerCase();\r\n const fileType = file.type.toLowerCase();\r\n\r\n return acceptedTokens.some((token) => {\r\n if (!token) {\r\n return false;\r\n }\r\n\r\n if (token.startsWith(\".\")) {\r\n return fileName.endsWith(token);\r\n }\r\n\r\n if (token.endsWith(\"/*\")) {\r\n const rootType = token.slice(0, token.length - 1);\r\n return fileType.startsWith(rootType);\r\n }\r\n\r\n return fileType === token;\r\n });\r\n}\r\n\r\nexport default function useDragdrop(options: SimpleDragDropParams = {}): UseDragDropResult {\r\n const {\r\n accept,\r\n maxFiles,\r\n maxFileSize,\r\n multiple = true,\r\n validation,\r\n value,\r\n onChange,\r\n onFileAdd,\r\n onFileAddB24,\r\n onFileRemove,\r\n showPreview = true,\r\n disabled = false\r\n } = options;\r\n\r\n const [files, setFiles] = useState<DragDropFileItem[]>([]);\r\n const [dragActive, setDragActive] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const inputRef = useRef<HTMLInputElement>(null);\r\n\r\n const emitFilesChange = useCallback((nextFiles: DragDropFileItem[]) => {\r\n const flatFiles = nextFiles.map((item) => item.file);\r\n if (onChange) {\r\n onChange(flatFiles);\r\n }\r\n }, [onChange]);\r\n\r\n useEffect(() => {\r\n if (!value) {\r\n return;\r\n }\r\n\r\n setFiles((previous) => {\r\n const previousByKey = new Map(previous.map((item) => [createFileKey(item.file), item]));\r\n const next = value.map((file) => {\r\n const key = createFileKey(file);\r\n const existing = previousByKey.get(key);\r\n if (existing) {\r\n return existing;\r\n }\r\n\r\n const isImage = file.type.startsWith(\"image/\");\r\n return {\r\n id: createFileId(file),\r\n file,\r\n isImage,\r\n previewUrl: showPreview && isImage ? URL.createObjectURL(file) : undefined\r\n };\r\n });\r\n\r\n const nextIds = new Set(next.map((item) => item.id));\r\n previous.forEach((item) => {\r\n if (!nextIds.has(item.id) && item.previewUrl) {\r\n URL.revokeObjectURL(item.previewUrl);\r\n }\r\n });\r\n\r\n return next;\r\n });\r\n }, [showPreview, value]);\r\n\r\n const maxSizeInBytes = useMemo(() => {\r\n if (!maxFileSize || maxFileSize <= 0) {\r\n return undefined;\r\n }\r\n\r\n return maxFileSize * bytesPerKilobyte * bytesPerKilobyte;\r\n }, [maxFileSize]);\r\n\r\n const addFiles = useCallback(async (incoming: FileList | File[]) => {\r\n if (disabled) {\r\n return;\r\n }\r\n\r\n setError(null);\r\n\r\n const inputFiles = Array.from(incoming);\r\n if (inputFiles.length === 0) {\r\n return;\r\n }\r\n\r\n const selectedFiles = multiple ? inputFiles : inputFiles.slice(0, 1);\r\n\r\n const nextFiles: DragDropFileItem[] = [];\r\n const fileErrors: string[] = [];\r\n\r\n for (const file of selectedFiles) {\r\n if (!doesFileMatchAccept(file, accept)) {\r\n fileErrors.push(`File type not accepted: ${file.name}`);\r\n continue;\r\n }\r\n\r\n if (maxSizeInBytes && file.size > maxSizeInBytes) {\r\n fileErrors.push(`File too large: ${file.name}`);\r\n continue;\r\n }\r\n\r\n if (validation && !validation(file)) {\r\n fileErrors.push(`Validation failed: ${file.name}`);\r\n continue;\r\n }\r\n\r\n const isImage = file.type.startsWith(\"image/\");\r\n nextFiles.push({\r\n id: createFileId(file),\r\n file,\r\n isImage,\r\n previewUrl: showPreview && isImage ? URL.createObjectURL(file) : undefined\r\n });\r\n }\r\n\r\n if (fileErrors.length > 0) {\r\n setError(fileErrors[0]);\r\n }\r\n\r\n if (nextFiles.length === 0) {\r\n return;\r\n }\r\n\r\n let removedByLimit: DragDropFileItem[] = [];\r\n let updatedFiles: DragDropFileItem[] = [];\r\n\r\n setFiles((previous) => {\r\n const merged = multiple ? [...previous, ...nextFiles] : [nextFiles[0]];\r\n\r\n if (!maxFiles || maxFiles <= 0) {\r\n updatedFiles = merged;\r\n return merged;\r\n }\r\n\r\n if (merged.length <= maxFiles) {\r\n updatedFiles = merged;\r\n return merged;\r\n }\r\n\r\n setError(`Maximum ${maxFiles} file${maxFiles > 1 ? \"s\" : \"\"} allowed`);\r\n removedByLimit = merged.slice(maxFiles);\r\n const limited = merged.slice(0, maxFiles);\r\n updatedFiles = limited;\r\n return limited;\r\n });\r\n\r\n if (removedByLimit.length > 0) {\r\n removedByLimit.forEach((item) => {\r\n if (item.previewUrl) {\r\n URL.revokeObjectURL(item.previewUrl);\r\n }\r\n });\r\n }\r\n\r\n if (onFileAdd || onFileAddB24) {\r\n for (const item of nextFiles) {\r\n if (onFileAdd) {\r\n onFileAdd(item.file);\r\n }\r\n\r\n if (onFileAddB24) {\r\n const base64 = await toBase64(item.file);\r\n onFileAddB24(base64);\r\n }\r\n }\r\n }\r\n\r\n emitFilesChange(updatedFiles);\r\n\r\n if (inputRef.current) {\r\n inputRef.current.value = \"\";\r\n }\r\n }, [accept, disabled, emitFilesChange, maxFiles, maxSizeInBytes, multiple, onFileAdd, onFileAddB24, showPreview, validation]);\r\n\r\n const removeFile = useCallback((id: string) => {\r\n let removedFile: DragDropFileItem | undefined;\r\n let updatedFiles: DragDropFileItem[] = [];\r\n\r\n setFiles((previous) => {\r\n removedFile = previous.find((item) => item.id === id);\r\n const next = previous.filter((item) => item.id !== id);\r\n updatedFiles = next;\r\n return next;\r\n });\r\n\r\n if (removedFile?.previewUrl) {\r\n URL.revokeObjectURL(removedFile.previewUrl);\r\n }\r\n\r\n if (removedFile?.file && onFileRemove) {\r\n onFileRemove(removedFile.file);\r\n }\r\n\r\n emitFilesChange(updatedFiles);\r\n }, [emitFilesChange, onFileRemove]);\r\n\r\n const clearFiles = useCallback(() => {\r\n setFiles((previous) => {\r\n previous.forEach((item) => {\r\n if (item.previewUrl) {\r\n URL.revokeObjectURL(item.previewUrl);\r\n }\r\n });\r\n\r\n return [];\r\n });\r\n\r\n emitFilesChange([]);\r\n }, [emitFilesChange]);\r\n\r\n useEffect(() => {\r\n return () => {\r\n files.forEach((item) => {\r\n if (item.previewUrl) {\r\n URL.revokeObjectURL(item.previewUrl);\r\n }\r\n });\r\n };\r\n }, [files]);\r\n\r\n const onDragEnter = useCallback((event: React.DragEvent<HTMLElement>) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n if (!disabled) {\r\n setDragActive(true);\r\n }\r\n }, [disabled]);\r\n\r\n const onDragOver = useCallback((event: React.DragEvent<HTMLElement>) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n if (!disabled) {\r\n setDragActive(true);\r\n }\r\n }, [disabled]);\r\n\r\n const onDragLeave = useCallback((event: React.DragEvent<HTMLElement>) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n setDragActive(false);\r\n }, []);\r\n\r\n const onDrop = useCallback(async (event: React.DragEvent<HTMLElement>) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n setDragActive(false);\r\n\r\n if (disabled) {\r\n return;\r\n }\r\n\r\n await addFiles(event.dataTransfer.files);\r\n }, [addFiles, disabled]);\r\n\r\n const onInputChange = useCallback(async (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const selected = event.target.files;\r\n\r\n if (!selected || disabled) {\r\n return;\r\n }\r\n\r\n await addFiles(selected);\r\n }, [addFiles, disabled]);\r\n\r\n const openFileDialog = useCallback(() => {\r\n if (!disabled) {\r\n inputRef.current?.click();\r\n }\r\n }, [disabled]);\r\n\r\n return {\r\n files,\r\n dragActive,\r\n error,\r\n inputRef,\r\n addFiles,\r\n removeFile,\r\n clearFiles,\r\n openFileDialog,\r\n onDragEnter,\r\n onDragOver,\r\n onDragLeave,\r\n onDrop,\r\n onInputChange\r\n };\r\n}\r\n"],"mappings":"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","names":["Image"]}