ics-ui-kit 0.1.6 → 0.1.7
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/file-upload/FileUpload.d.ts +1 -0
- package/dist/components/file-upload/FileUpload.stories.d.ts +1 -0
- package/dist/components/file-upload/components/file-upload-compact-input-zone/FileUploadCompactInputZone.d.ts +1 -1
- package/dist/components/file-upload/components/file-upload-input-zone/FileUploadInputZone.d.ts +1 -1
- package/dist/components/file-upload/components/file-upload-item/FileUploadItem.d.ts +2 -0
- package/dist/components/file-upload/components/file-upload-item/FileUploadItem.stories.d.ts +1 -0
- package/dist/components/file-upload/components/file-upload-item-compact/FileUploadItemCompact.d.ts +2 -0
- package/dist/components/file-upload/components/file-upload-item-compact/FileUploadItemCompact.stories.d.ts +1 -0
- package/dist/components/file-upload/file-upload-compact/FileUploadCompact.d.ts +1 -0
- package/dist/components/file-upload/file-upload-compact/FileUploadCompact.stories.d.ts +1 -0
- package/dist/components/file-upload.js +194 -185
- package/dist/components/file-upload.js.map +1 -1
- package/dist/components/resizable/components/ResizableCornerIcon.d.ts +3 -0
- package/dist/components/resizable/components/ResizableCornerIcon.stories.d.ts +7 -0
- package/dist/components/resizable/index.d.ts +1 -0
- package/dist/components/resizable.js +255 -232
- package/dist/components/resizable.js.map +1 -1
- package/dist/formatBytes-C4QXq5lC.js +9 -0
- package/dist/formatBytes-C4QXq5lC.js.map +1 -0
- package/dist/hooks/use-file-upload.js +1 -1
- package/dist/lib/utils/index.d.ts +1 -0
- package/dist/lib/utils.js +4 -2
- package/dist/lib/utils.js.map +1 -1
- package/dist/styles-scoped.css +8 -2
- package/dist/styles.css +8 -2
- package/dist/useFileUpload-Bnl3P8mP.js +193 -0
- package/dist/useFileUpload-Bnl3P8mP.js.map +1 -0
- package/package.json +1 -1
- package/tailwind.preset.js +2 -2
- package/dist/useFileUpload-iDag0iqM.js +0 -197
- package/dist/useFileUpload-iDag0iqM.js.map +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const e = (t, o = 2) => {
|
|
2
|
+
if (t === 0) return "0 Bytes";
|
|
3
|
+
const B = 1024, s = o < 0 ? 0 : o, a = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], r = Math.floor(Math.log(t) / Math.log(B));
|
|
4
|
+
return `${Number.parseFloat((t / Math.pow(B, r)).toFixed(s))} ${a[r]}`;
|
|
5
|
+
};
|
|
6
|
+
export {
|
|
7
|
+
e as f
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=formatBytes-C4QXq5lC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatBytes-C4QXq5lC.js","sources":["../src/lib/utils/file/formatBytes.ts"],"sourcesContent":["// Helper function to format bytes to human-readable format\nexport const formatBytes = (bytes: number, decimals = 2): string => {\n\tif (bytes === 0) return \"0 Bytes\";\n\n\tconst k = 1024;\n\tconst dm = decimals < 0 ? 0 : decimals;\n\tconst sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\n\treturn `${Number.parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;\n};\n"],"names":["formatBytes","bytes","decimals","k","dm","sizes","i"],"mappings":"AACO,MAAMA,IAAc,CAACC,GAAeC,IAAW,MAAc;AAC/D,MAAAD,MAAU,EAAU,QAAA;AAExB,QAAME,IAAI,MACJC,IAAKF,IAAW,IAAI,IAAIA,GACxBG,IAAQ,CAAC,SAAS,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,IAAI,GAEhEC,IAAI,KAAK,MAAM,KAAK,IAAIL,CAAK,IAAI,KAAK,IAAIE,CAAC,CAAC;AAElD,SAAO,GAAG,OAAO,YAAYF,IAAQ,KAAK,IAAIE,GAAGG,CAAC,GAAG,QAAQF,CAAE,CAAC,CAAC,IAAIC,EAAMC,CAAC,CAAC;AAC9E;"}
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { c as
|
|
1
|
+
import { c as i } from "../cn-dsXlqdJg.js";
|
|
2
|
+
import { f as c } from "../formatBytes-C4QXq5lC.js";
|
|
2
3
|
function n(r) {
|
|
3
4
|
if (r === 0 || r < 0)
|
|
4
5
|
return "";
|
|
@@ -19,7 +20,8 @@ function n(r) {
|
|
|
19
20
|
return String(r);
|
|
20
21
|
}
|
|
21
22
|
export {
|
|
22
|
-
|
|
23
|
+
i as cn,
|
|
24
|
+
c as formatBytes,
|
|
23
25
|
n as formatCounterValue
|
|
24
26
|
};
|
|
25
27
|
//# sourceMappingURL=utils.js.map
|
package/dist/lib/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../src/lib/utils/formatCounterValue.ts"],"sourcesContent":["/**\n * Форматирует число для отображения в компоненте Counter согласно правилам:\n * - Максимум 4 символа, включая `+`\n * - 0 не отображается\n * - Без дробей\n *\n * @param value - Число для форматирования\n * @returns Отформатированная строка или пустая строка для 0\n *\n * @example\n * formatCounterValue(5) // \"5\"\n * formatCounterValue(42) // \"42\"\n * formatCounterValue(150) // \"99+\"\n * formatCounterValue(5000) // \"999+\"\n * formatCounterValue(50000) // \"10k+\"\n * formatCounterValue(2000000) // \"2М+\"\n * formatCounterValue(10000000) // \"10М+\"\n * formatCounterValue(99000000) // \"99М+\"\n * formatCounterValue(0) // \"\"\n */\nexport function formatCounterValue(value: number): string {\n\t// 0 не отображаем\n\tif (value === 0) {\n\t\treturn \"\";\n\t}\n\n\t// Отрицательные числа не поддерживаются\n\tif (value < 0) {\n\t\treturn \"\";\n\t}\n\n\t// 1-9: показать одну цифру\n\tif (value >= 1 && value <= 9) {\n\t\treturn String(value);\n\t}\n\n\t// 10-99: показать две цифры\n\tif (value >= 10 && value <= 99) {\n\t\treturn String(value);\n\t}\n\n\t// 100-999: показать \"99+\"\n\tif (value >= 100 && value <= 999) {\n\t\treturn \"99+\";\n\t}\n\n\t// 1 000-9 999: показать \"999+\"\n\tif (value >= 1000 && value <= 9999) {\n\t\treturn \"999+\";\n\t}\n\n\t// 10 000-999 999: показать \"10k+\", \"99k+\" и т.д.\n\tif (value >= 10000 && value <= 999999) {\n\t\tconst thousands = Math.floor(value / 1000);\n\t\t// Проверяем, что результат не превышает 4 символа\n\t\tif (thousands <= 99) {\n\t\t\treturn `${thousands}k+`;\n\t\t}\n\t\t// Если больше 99k, показываем 99k+\n\t\treturn \"99k+\";\n\t}\n\n\t// ≥ 1 000 000: показать \"1М+\", \"9М+\", \"10М+\", \"99М+\" и т.д.\n\tif (value >= 1000000) {\n\t\tconst millions = Math.floor(value / 1000000);\n\t\t// 1-9 млн и 10-98 млн\"\n\t\tif ((millions >= 1 && millions <= 9) || (millions >= 10 && millions <= 98)) {\n\t\t\treturn `${millions}М+`;\n\t\t}\n\t\t// 99 млн и выше: всегда \"99М+\"\n\t\treturn \"99М+\";\n\t}\n\n\t// Fallback (не должно произойти)\n\treturn String(value);\n}\n"],"names":["formatCounterValue","value","thousands","millions"],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/lib/utils/formatCounterValue.ts"],"sourcesContent":["/**\n * Форматирует число для отображения в компоненте Counter согласно правилам:\n * - Максимум 4 символа, включая `+`\n * - 0 не отображается\n * - Без дробей\n *\n * @param value - Число для форматирования\n * @returns Отформатированная строка или пустая строка для 0\n *\n * @example\n * formatCounterValue(5) // \"5\"\n * formatCounterValue(42) // \"42\"\n * formatCounterValue(150) // \"99+\"\n * formatCounterValue(5000) // \"999+\"\n * formatCounterValue(50000) // \"10k+\"\n * formatCounterValue(2000000) // \"2М+\"\n * formatCounterValue(10000000) // \"10М+\"\n * formatCounterValue(99000000) // \"99М+\"\n * formatCounterValue(0) // \"\"\n */\nexport function formatCounterValue(value: number): string {\n\t// 0 не отображаем\n\tif (value === 0) {\n\t\treturn \"\";\n\t}\n\n\t// Отрицательные числа не поддерживаются\n\tif (value < 0) {\n\t\treturn \"\";\n\t}\n\n\t// 1-9: показать одну цифру\n\tif (value >= 1 && value <= 9) {\n\t\treturn String(value);\n\t}\n\n\t// 10-99: показать две цифры\n\tif (value >= 10 && value <= 99) {\n\t\treturn String(value);\n\t}\n\n\t// 100-999: показать \"99+\"\n\tif (value >= 100 && value <= 999) {\n\t\treturn \"99+\";\n\t}\n\n\t// 1 000-9 999: показать \"999+\"\n\tif (value >= 1000 && value <= 9999) {\n\t\treturn \"999+\";\n\t}\n\n\t// 10 000-999 999: показать \"10k+\", \"99k+\" и т.д.\n\tif (value >= 10000 && value <= 999999) {\n\t\tconst thousands = Math.floor(value / 1000);\n\t\t// Проверяем, что результат не превышает 4 символа\n\t\tif (thousands <= 99) {\n\t\t\treturn `${thousands}k+`;\n\t\t}\n\t\t// Если больше 99k, показываем 99k+\n\t\treturn \"99k+\";\n\t}\n\n\t// ≥ 1 000 000: показать \"1М+\", \"9М+\", \"10М+\", \"99М+\" и т.д.\n\tif (value >= 1000000) {\n\t\tconst millions = Math.floor(value / 1000000);\n\t\t// 1-9 млн и 10-98 млн\"\n\t\tif ((millions >= 1 && millions <= 9) || (millions >= 10 && millions <= 98)) {\n\t\t\treturn `${millions}М+`;\n\t\t}\n\t\t// 99 млн и выше: всегда \"99М+\"\n\t\treturn \"99М+\";\n\t}\n\n\t// Fallback (не должно произойти)\n\treturn String(value);\n}\n"],"names":["formatCounterValue","value","thousands","millions"],"mappings":";;AAoBO,SAASA,EAAmBC,GAAuB;AAOzD,MALIA,MAAU,KAKVA,IAAQ;AACJ,WAAA;AASJ,MALAA,KAAS,KAAKA,KAAS,KAKvBA,KAAS,MAAMA,KAAS;AAC3B,WAAO,OAAOA,CAAK;AAIhB,MAAAA,KAAS,OAAOA,KAAS;AACrB,WAAA;AAIJ,MAAAA,KAAS,OAAQA,KAAS;AACtB,WAAA;AAIJ,MAAAA,KAAS,OAASA,KAAS,QAAQ;AACtC,UAAMC,IAAY,KAAK,MAAMD,IAAQ,GAAI;AAEzC,WAAIC,KAAa,KACT,GAAGA,CAAS,OAGb;AAAA,EAAA;AAIR,MAAID,KAAS,KAAS;AACrB,UAAME,IAAW,KAAK,MAAMF,IAAQ,GAAO;AAE3C,WAAKE,KAAY,KAAKA,KAAY,KAAOA,KAAY,MAAMA,KAAY,KAC/D,GAAGA,CAAQ,OAGZ;AAAA,EAAA;AAIR,SAAO,OAAOF,CAAK;AACpB;"}
|
package/dist/styles-scoped.css
CHANGED
|
@@ -1442,6 +1442,9 @@
|
|
|
1442
1442
|
.ui-kit .right-0 {
|
|
1443
1443
|
right: 0px;
|
|
1444
1444
|
}
|
|
1445
|
+
.ui-kit .right-0\.5 {
|
|
1446
|
+
right: 0.125rem;
|
|
1447
|
+
}
|
|
1445
1448
|
.ui-kit .right-1 {
|
|
1446
1449
|
right: 0.25rem;
|
|
1447
1450
|
}
|
|
@@ -3004,13 +3007,13 @@
|
|
|
3004
3007
|
background-color: hsl(var(--alpha-50));
|
|
3005
3008
|
}
|
|
3006
3009
|
.ui-kit .bg-alpha-60 {
|
|
3007
|
-
background-color: hsl(var(--alpha-
|
|
3010
|
+
background-color: hsl(var(--alpha-40));
|
|
3008
3011
|
}
|
|
3009
3012
|
.ui-kit .bg-alpha-high-20 {
|
|
3010
3013
|
background-color: hsl(var(--alpha-high-80));
|
|
3011
3014
|
}
|
|
3012
3015
|
.ui-kit .bg-alpha-high-60 {
|
|
3013
|
-
background-color: hsl(var(--alpha-high-
|
|
3016
|
+
background-color: hsl(var(--alpha-high-40));
|
|
3014
3017
|
}
|
|
3015
3018
|
.ui-kit .bg-alpha-high-80 {
|
|
3016
3019
|
background-color: hsl(var(--alpha-high-20));
|
|
@@ -6105,6 +6108,9 @@
|
|
|
6105
6108
|
visibility: visible;
|
|
6106
6109
|
}
|
|
6107
6110
|
}
|
|
6111
|
+
.ui-kit .\[\&\:\:-webkit-resizer\]\:appearance-none::-webkit-resizer {
|
|
6112
|
+
appearance: none;
|
|
6113
|
+
}
|
|
6108
6114
|
.ui-kit .\[\&\:\:-webkit-search-cancel-button\]\:hidden::-webkit-search-cancel-button {
|
|
6109
6115
|
display: none;
|
|
6110
6116
|
}
|
package/dist/styles.css
CHANGED
|
@@ -1427,6 +1427,9 @@ body {
|
|
|
1427
1427
|
.right-0 {
|
|
1428
1428
|
right: 0px;
|
|
1429
1429
|
}
|
|
1430
|
+
.right-0\.5 {
|
|
1431
|
+
right: 0.125rem;
|
|
1432
|
+
}
|
|
1430
1433
|
.right-1 {
|
|
1431
1434
|
right: 0.25rem;
|
|
1432
1435
|
}
|
|
@@ -2989,13 +2992,13 @@ body {
|
|
|
2989
2992
|
background-color: hsl(var(--alpha-50));
|
|
2990
2993
|
}
|
|
2991
2994
|
.bg-alpha-60 {
|
|
2992
|
-
background-color: hsl(var(--alpha-
|
|
2995
|
+
background-color: hsl(var(--alpha-40));
|
|
2993
2996
|
}
|
|
2994
2997
|
.bg-alpha-high-20 {
|
|
2995
2998
|
background-color: hsl(var(--alpha-high-80));
|
|
2996
2999
|
}
|
|
2997
3000
|
.bg-alpha-high-60 {
|
|
2998
|
-
background-color: hsl(var(--alpha-high-
|
|
3001
|
+
background-color: hsl(var(--alpha-high-40));
|
|
2999
3002
|
}
|
|
3000
3003
|
.bg-alpha-high-80 {
|
|
3001
3004
|
background-color: hsl(var(--alpha-high-20));
|
|
@@ -6094,6 +6097,9 @@ body {
|
|
|
6094
6097
|
visibility: visible;
|
|
6095
6098
|
}
|
|
6096
6099
|
}
|
|
6100
|
+
.\[\&\:\:-webkit-resizer\]\:appearance-none::-webkit-resizer {
|
|
6101
|
+
appearance: none;
|
|
6102
|
+
}
|
|
6097
6103
|
.\[\&\:\:-webkit-search-cancel-button\]\:hidden::-webkit-search-cancel-button {
|
|
6098
6104
|
display: none;
|
|
6099
6105
|
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { useMemo as W, useState as k, useRef as O, useCallback as n } from "react";
|
|
2
|
+
import { f as h } from "./formatBytes-C4QXq5lC.js";
|
|
3
|
+
const j = {
|
|
4
|
+
fileTooLarge: (s, c) => `File "${s}" exceeds the maximum size of ${h(c)}.`,
|
|
5
|
+
invalidFileType: (s) => `File "${s}" is not an accepted file type.`,
|
|
6
|
+
tooManyFiles: (s) => `You can only upload a maximum of ${s} files.`,
|
|
7
|
+
someFilesTooLarge: (s) => `Some files exceed the maximum size of ${h(s)}.`,
|
|
8
|
+
singleFileTooLarge: (s) => `File exceeds the maximum size of ${h(s)}.`
|
|
9
|
+
}, N = {
|
|
10
|
+
fileTooLarge: (s, c) => `Файл "${s}" превышает максимальный размер ${h(c)}`,
|
|
11
|
+
invalidFileType: (s) => `Файл "${s}" имеет недопустимый тип`,
|
|
12
|
+
tooManyFiles: (s) => `Можно загрузить максимум ${s} файлов`,
|
|
13
|
+
someFilesTooLarge: (s) => `Некоторые файлы превышают максимальный размер ${h(s)}`,
|
|
14
|
+
singleFileTooLarge: (s) => `Файл превышает максимальный размер ${h(s)}`
|
|
15
|
+
}, Y = (s = {}) => {
|
|
16
|
+
const {
|
|
17
|
+
maxFiles: c = 1 / 0,
|
|
18
|
+
maxSize: g = 1 / 0,
|
|
19
|
+
accept: T = "*",
|
|
20
|
+
multiple: o = !1,
|
|
21
|
+
initialFiles: z = [],
|
|
22
|
+
onFilesChange: m,
|
|
23
|
+
onFilesAdded: D,
|
|
24
|
+
errorMessages: w
|
|
25
|
+
} = s, p = W(() => ({ ...j, ...w }), [w]), [v, l] = k({
|
|
26
|
+
files: z.map((e) => ({
|
|
27
|
+
file: e,
|
|
28
|
+
id: e.id,
|
|
29
|
+
preview: e.url
|
|
30
|
+
})),
|
|
31
|
+
isDragging: !1,
|
|
32
|
+
errors: []
|
|
33
|
+
}), f = O(null), x = n(
|
|
34
|
+
(e) => {
|
|
35
|
+
const r = (e instanceof File, e.name);
|
|
36
|
+
if (e.size > g)
|
|
37
|
+
return p.fileTooLarge(r, g);
|
|
38
|
+
if (T !== "*") {
|
|
39
|
+
const i = T.split(",").map((u) => u.trim()), a = e instanceof File ? e.type || "" : e.type, t = `.${r.split(".").pop()}`;
|
|
40
|
+
if (!i.some((u) => {
|
|
41
|
+
if (u.startsWith("."))
|
|
42
|
+
return t.toLowerCase() === u.toLowerCase();
|
|
43
|
+
if (u.endsWith("/*")) {
|
|
44
|
+
const y = u.split("/")[0];
|
|
45
|
+
return a.startsWith(`${y}/`);
|
|
46
|
+
}
|
|
47
|
+
return a === u;
|
|
48
|
+
}))
|
|
49
|
+
return p.invalidFileType(r);
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
},
|
|
53
|
+
[T, g, p]
|
|
54
|
+
), M = n((e) => e instanceof File ? URL.createObjectURL(e) : e.url, []), R = n((e) => e instanceof File ? `${e.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}` : e.id, []), L = n(() => {
|
|
55
|
+
l((e) => {
|
|
56
|
+
e.files.forEach((i) => {
|
|
57
|
+
i.preview && i.file instanceof File && i.file.type.startsWith("image/") && URL.revokeObjectURL(i.preview);
|
|
58
|
+
}), f.current && (f.current.value = "");
|
|
59
|
+
const r = {
|
|
60
|
+
...e,
|
|
61
|
+
files: [],
|
|
62
|
+
errors: []
|
|
63
|
+
};
|
|
64
|
+
return m?.(r.files), r;
|
|
65
|
+
});
|
|
66
|
+
}, [m]), d = n(
|
|
67
|
+
(e) => {
|
|
68
|
+
if (!e || e.length === 0) return;
|
|
69
|
+
const r = Array.from(e), i = [];
|
|
70
|
+
if (l((t) => ({ ...t, errors: [] })), o || L(), o && c !== 1 / 0 && v.files.length + r.length > c) {
|
|
71
|
+
i.push(p.tooManyFiles(c)), l((t) => ({ ...t, errors: i }));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const a = [];
|
|
75
|
+
r.forEach((t) => {
|
|
76
|
+
if (o && v.files.some(
|
|
77
|
+
(y) => y.file.name === t.name && y.file.size === t.size
|
|
78
|
+
))
|
|
79
|
+
return;
|
|
80
|
+
if (t.size > g) {
|
|
81
|
+
i.push(
|
|
82
|
+
o ? p.someFilesTooLarge(g) : p.singleFileTooLarge(g)
|
|
83
|
+
);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const F = x(t);
|
|
87
|
+
F ? i.push(F) : a.push({
|
|
88
|
+
file: t,
|
|
89
|
+
id: R(t),
|
|
90
|
+
preview: M(t)
|
|
91
|
+
});
|
|
92
|
+
}), a.length > 0 ? (D?.(a), l((t) => {
|
|
93
|
+
const F = o ? [...t.files, ...a] : a;
|
|
94
|
+
return m?.(F), {
|
|
95
|
+
...t,
|
|
96
|
+
files: F,
|
|
97
|
+
errors: i
|
|
98
|
+
};
|
|
99
|
+
})) : i.length > 0 && l((t) => ({
|
|
100
|
+
...t,
|
|
101
|
+
errors: i
|
|
102
|
+
})), f.current && (f.current.value = "");
|
|
103
|
+
},
|
|
104
|
+
[
|
|
105
|
+
v.files,
|
|
106
|
+
c,
|
|
107
|
+
o,
|
|
108
|
+
g,
|
|
109
|
+
x,
|
|
110
|
+
M,
|
|
111
|
+
R,
|
|
112
|
+
L,
|
|
113
|
+
m,
|
|
114
|
+
D,
|
|
115
|
+
p
|
|
116
|
+
]
|
|
117
|
+
), E = n(
|
|
118
|
+
(e) => {
|
|
119
|
+
l((r) => {
|
|
120
|
+
const i = r.files.find((t) => t.id === e);
|
|
121
|
+
i && i.preview && i.file instanceof File && i.file.type.startsWith("image/") && URL.revokeObjectURL(i.preview);
|
|
122
|
+
const a = r.files.filter((t) => t.id !== e);
|
|
123
|
+
return m?.(a), {
|
|
124
|
+
...r,
|
|
125
|
+
files: a,
|
|
126
|
+
errors: []
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
[m]
|
|
131
|
+
), U = n(() => {
|
|
132
|
+
l((e) => ({
|
|
133
|
+
...e,
|
|
134
|
+
errors: []
|
|
135
|
+
}));
|
|
136
|
+
}, []), b = n((e) => {
|
|
137
|
+
e.preventDefault(), e.stopPropagation(), l((r) => ({ ...r, isDragging: !0 }));
|
|
138
|
+
}, []), C = n((e) => {
|
|
139
|
+
e.preventDefault(), e.stopPropagation(), !e.currentTarget.contains(e.relatedTarget) && l((r) => ({ ...r, isDragging: !1 }));
|
|
140
|
+
}, []), P = n((e) => {
|
|
141
|
+
e.preventDefault(), e.stopPropagation();
|
|
142
|
+
}, []), S = n(
|
|
143
|
+
(e) => {
|
|
144
|
+
if (e.preventDefault(), e.stopPropagation(), l((r) => ({ ...r, isDragging: !1 })), !f.current?.disabled && e.dataTransfer.files && e.dataTransfer.files.length > 0)
|
|
145
|
+
if (o)
|
|
146
|
+
d(e.dataTransfer.files);
|
|
147
|
+
else {
|
|
148
|
+
const r = e.dataTransfer.files[0];
|
|
149
|
+
d([r]);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
[d, o]
|
|
153
|
+
), $ = n(
|
|
154
|
+
(e) => {
|
|
155
|
+
e.target.files && e.target.files.length > 0 && d(e.target.files);
|
|
156
|
+
},
|
|
157
|
+
[d]
|
|
158
|
+
), A = n(() => {
|
|
159
|
+
f.current && f.current.click();
|
|
160
|
+
}, []), I = n(
|
|
161
|
+
(e = {}) => ({
|
|
162
|
+
...e,
|
|
163
|
+
type: "file",
|
|
164
|
+
onChange: $,
|
|
165
|
+
accept: e.accept || T,
|
|
166
|
+
multiple: e.multiple !== void 0 ? e.multiple : o,
|
|
167
|
+
ref: f
|
|
168
|
+
}),
|
|
169
|
+
[T, o, $]
|
|
170
|
+
);
|
|
171
|
+
return [
|
|
172
|
+
v,
|
|
173
|
+
{
|
|
174
|
+
addFiles: d,
|
|
175
|
+
removeFile: E,
|
|
176
|
+
clearFiles: L,
|
|
177
|
+
clearErrors: U,
|
|
178
|
+
handleDragEnter: b,
|
|
179
|
+
handleDragLeave: C,
|
|
180
|
+
handleDragOver: P,
|
|
181
|
+
handleDrop: S,
|
|
182
|
+
handleFileChange: $,
|
|
183
|
+
openFileDialog: A,
|
|
184
|
+
getInputProps: I
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
};
|
|
188
|
+
export {
|
|
189
|
+
N as a,
|
|
190
|
+
j as d,
|
|
191
|
+
Y as u
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=useFileUpload-Bnl3P8mP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFileUpload-Bnl3P8mP.js","sources":["../src/hooks/use-file-upload/errorMessages.ts","../src/hooks/use-file-upload/useFileUpload.ts"],"sourcesContent":["import { formatBytes } from \"@/lib/utils/file/formatBytes\";\n\n/**\n * Интерфейс для кастомизации сообщений об ошибках в useFileUpload\n */\nexport interface FileUploadErrorMessages {\n\t/**\n\t * Сообщение когда файл превышает максимальный размер\n\t * @param fileName - имя файла\n\t * @param maxSizeBytes - максимальный размер в байтах\n\t */\n\tfileTooLarge?: (fileName: string, maxSizeBytes: number) => string;\n\n\t/**\n\t * Сообщение когда тип файла не разрешен\n\t * @param fileName - имя файла\n\t */\n\tinvalidFileType?: (fileName: string) => string;\n\n\t/**\n\t * Сообщение когда превышено максимальное количество файлов\n\t * @param maxFiles - максимальное количество файлов\n\t */\n\ttooManyFiles?: (maxFiles: number) => string;\n\n\t/**\n\t * Сообщение когда некоторые файлы превышают максимальный размер (для множественной загрузки)\n\t * @param maxSizeBytes - максимальный размер в байтах\n\t */\n\tsomeFilesTooLarge?: (maxSizeBytes: number) => string;\n\n\t/**\n\t * Сообщение когда файл превышает максимальный размер (для одиночной загрузки)\n\t * @param maxSizeBytes - максимальный размер в байтах\n\t */\n\tsingleFileTooLarge?: (maxSizeBytes: number) => string;\n}\n\n/**\n * Сообщения об ошибках по умолчанию\n */\nexport const defaultErrorMessages: Required<FileUploadErrorMessages> = {\n\tfileTooLarge: (fileName, maxSizeBytes) =>\n\t\t`File \"${fileName}\" exceeds the maximum size of ${formatBytes(maxSizeBytes)}.`,\n\tinvalidFileType: (fileName) => `File \"${fileName}\" is not an accepted file type.`,\n\ttooManyFiles: (maxFiles) => `You can only upload a maximum of ${maxFiles} files.`,\n\tsomeFilesTooLarge: (maxSizeBytes) => `Some files exceed the maximum size of ${formatBytes(maxSizeBytes)}.`,\n\tsingleFileTooLarge: (maxSizeBytes) => `File exceeds the maximum size of ${formatBytes(maxSizeBytes)}.`\n};\n\n/**\n * Сообщения об ошибках на русском языке\n */\nexport const defaultErrorMessagesRu: Required<FileUploadErrorMessages> = {\n\tfileTooLarge: (fileName, maxSizeBytes) =>\n\t\t`Файл \"${fileName}\" превышает максимальный размер ${formatBytes(maxSizeBytes)}`,\n\tinvalidFileType: (fileName) => `Файл \"${fileName}\" имеет недопустимый тип`,\n\ttooManyFiles: (maxFiles) => `Можно загрузить максимум ${maxFiles} файлов`,\n\tsomeFilesTooLarge: (maxSizeBytes) => `Некоторые файлы превышают максимальный размер ${formatBytes(maxSizeBytes)}`,\n\tsingleFileTooLarge: (maxSizeBytes) => `Файл превышает максимальный размер ${formatBytes(maxSizeBytes)}`\n};\n","import {\n\tuseCallback,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n\ttype ChangeEvent,\n\ttype DragEvent,\n\ttype InputHTMLAttributes\n} from \"react\";\nimport { defaultErrorMessages, type FileUploadErrorMessages } from \"./errorMessages\";\n\nexport type FileData = {\n\tname: string;\n\tsize: number;\n\ttype: string;\n\tid?: string;\n};\n\nexport type FileMetadata = FileData & {\n\turl: string;\n\tid: string;\n};\n\nexport type FileValue = File | FileData;\n\nexport type FileWithPreview = {\n\tfile: FileValue;\n\tid: string;\n\tpreview?: string;\n};\n\n/**\n * Ограничения для загрузки файлов\n */\nexport type FileUploadConstraints = {\n\t/**\n\t * Максимальное количество файлов\n\t * Используется только когда multiple=true\n\t * @default Infinity\n\t */\n\tmaxFiles?: number;\n\n\t/**\n\t * Максимальный размер файла в байтах\n\t * @default Infinity\n\t */\n\tmaxSize?: number;\n\n\t/**\n\t * Допустимые типы файлов (строка MIME-типов или расширений через запятую)\n\t * @example \"image/jpeg,image/png,.pdf,.doc\"\n\t * @example \"*.jpg,*.png\"\n\t * @example \"image/*\"\n\t * @default \"*\"\n\t */\n\taccept?: string;\n\n\t/**\n\t * Разрешить выбор нескольких файлов\n\t * @default false\n\t */\n\tmultiple?: boolean;\n};\n\nexport type FileUploadOptions = FileUploadConstraints & {\n\tinitialFiles?: FileMetadata[];\n\tonFilesChange?: (files: FileWithPreview[]) => void;\n\tonFilesAdded?: (addedFiles: FileWithPreview[]) => void;\n\t/**\n\t * Кастомные сообщения об ошибках\n\t * Можно переопределить только нужные сообщения\n\t */\n\terrorMessages?: Partial<FileUploadErrorMessages>;\n};\n\nexport type FileUploadState = {\n\tfiles: FileWithPreview[];\n\tisDragging: boolean;\n\terrors: string[];\n};\n\nexport type FileUploadActions = {\n\taddFiles: (files: FileList | File[]) => void;\n\tremoveFile: (id: string) => void;\n\tclearFiles: () => void;\n\tclearErrors: () => void;\n\thandleDragEnter: (e: DragEvent<HTMLElement>) => void;\n\thandleDragLeave: (e: DragEvent<HTMLElement>) => void;\n\thandleDragOver: (e: DragEvent<HTMLElement>) => void;\n\thandleDrop: (e: DragEvent<HTMLElement>) => void;\n\thandleFileChange: (e: ChangeEvent<HTMLInputElement>) => void;\n\topenFileDialog: () => void;\n\tgetInputProps: (props?: InputHTMLAttributes<HTMLInputElement>) => InputHTMLAttributes<HTMLInputElement> & {\n\t\tref: React.Ref<HTMLInputElement>;\n\t};\n};\n\n/** Хук был взять из библиотеки originui.\n * Код можно посмотреть по ссылке: https://github.com/origin-space/originui/blob/main/docs/use-file-upload.md\n */\nexport const useFileUpload = (options: FileUploadOptions = {}): [FileUploadState, FileUploadActions] => {\n\tconst {\n\t\tmaxFiles = Infinity,\n\t\tmaxSize = Infinity,\n\t\taccept = \"*\",\n\t\tmultiple = false,\n\t\tinitialFiles = [],\n\t\tonFilesChange,\n\t\tonFilesAdded,\n\t\terrorMessages: customErrorMessages\n\t} = options;\n\n\t// Объединяем дефолтные и кастомные сообщения\n\tconst errorMessages = useMemo(() => ({ ...defaultErrorMessages, ...customErrorMessages }), [customErrorMessages]);\n\n\tconst [state, setState] = useState<FileUploadState>({\n\t\tfiles: initialFiles.map((file) => ({\n\t\t\tfile,\n\t\t\tid: file.id,\n\t\t\tpreview: file.url\n\t\t})),\n\t\tisDragging: false,\n\t\terrors: []\n\t});\n\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\n\tconst validateFile = useCallback(\n\t\t(file: FileValue): string | null => {\n\t\t\tconst fileName = file instanceof File ? file.name : file.name;\n\n\t\t\tif (file.size > maxSize) {\n\t\t\t\treturn errorMessages.fileTooLarge(fileName, maxSize);\n\t\t\t}\n\n\t\t\tif (accept !== \"*\") {\n\t\t\t\tconst acceptedTypes = accept.split(\",\").map((type) => type.trim());\n\t\t\t\tconst fileType = file instanceof File ? file.type || \"\" : file.type;\n\t\t\t\tconst fileExtension = `.${fileName.split(\".\").pop()}`;\n\n\t\t\t\tconst isAccepted = acceptedTypes.some((type) => {\n\t\t\t\t\tif (type.startsWith(\".\")) {\n\t\t\t\t\t\treturn fileExtension.toLowerCase() === type.toLowerCase();\n\t\t\t\t\t}\n\t\t\t\t\tif (type.endsWith(\"/*\")) {\n\t\t\t\t\t\tconst baseType = type.split(\"/\")[0];\n\t\t\t\t\t\treturn fileType.startsWith(`${baseType}/`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fileType === type;\n\t\t\t\t});\n\n\t\t\t\tif (!isAccepted) {\n\t\t\t\t\treturn errorMessages.invalidFileType(fileName);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\t\t[accept, maxSize, errorMessages]\n\t);\n\n\tconst createPreview = useCallback((file: File | FileMetadata): string | undefined => {\n\t\tif (file instanceof File) {\n\t\t\treturn URL.createObjectURL(file);\n\t\t}\n\t\treturn file.url;\n\t}, []);\n\n\tconst generateUniqueId = useCallback((file: File | FileMetadata): string => {\n\t\tif (file instanceof File) {\n\t\t\treturn `${file.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n\t\t}\n\t\treturn file.id;\n\t}, []);\n\n\tconst clearFiles = useCallback(() => {\n\t\tsetState((prev) => {\n\t\t\t// Clean up object URLs\n\t\t\tprev.files.forEach((file) => {\n\t\t\t\tif (file.preview && file.file instanceof File && file.file.type.startsWith(\"image/\")) {\n\t\t\t\t\tURL.revokeObjectURL(file.preview);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (inputRef.current) {\n\t\t\t\tinputRef.current.value = \"\";\n\t\t\t}\n\n\t\t\tconst newState = {\n\t\t\t\t...prev,\n\t\t\t\tfiles: [],\n\t\t\t\terrors: []\n\t\t\t};\n\n\t\t\tonFilesChange?.(newState.files);\n\t\t\treturn newState;\n\t\t});\n\t}, [onFilesChange]);\n\n\tconst addFiles = useCallback(\n\t\t(newFiles: FileList | File[]) => {\n\t\t\tif (!newFiles || newFiles.length === 0) return;\n\n\t\t\tconst newFilesArray = Array.from(newFiles);\n\t\t\tconst errors: string[] = [];\n\n\t\t\t// Clear existing errors when new files are uploaded\n\t\t\tsetState((prev) => ({ ...prev, errors: [] }));\n\n\t\t\t// In single file mode, clear existing files first\n\t\t\tif (!multiple) {\n\t\t\t\tclearFiles();\n\t\t\t}\n\n\t\t\t// Check if adding these files would exceed maxFiles (only in multiple mode)\n\t\t\tif (multiple && maxFiles !== Infinity && state.files.length + newFilesArray.length > maxFiles) {\n\t\t\t\terrors.push(errorMessages.tooManyFiles(maxFiles));\n\t\t\t\tsetState((prev) => ({ ...prev, errors }));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst validFiles: FileWithPreview[] = [];\n\n\t\t\tnewFilesArray.forEach((file) => {\n\t\t\t\t// Only check for duplicates if multiple files are allowed\n\t\t\t\tif (multiple) {\n\t\t\t\t\tconst isDuplicate = state.files.some(\n\t\t\t\t\t\t(existingFile) => existingFile.file.name === file.name && existingFile.file.size === file.size\n\t\t\t\t\t);\n\n\t\t\t\t\t// Skip duplicate files silently\n\t\t\t\t\tif (isDuplicate) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check file size\n\t\t\t\tif (file.size > maxSize) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\tmultiple ? errorMessages.someFilesTooLarge(maxSize) : errorMessages.singleFileTooLarge(maxSize)\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst error = validateFile(file);\n\t\t\t\tif (error) {\n\t\t\t\t\terrors.push(error);\n\t\t\t\t} else {\n\t\t\t\t\tvalidFiles.push({\n\t\t\t\t\t\tfile,\n\t\t\t\t\t\tid: generateUniqueId(file),\n\t\t\t\t\t\tpreview: createPreview(file)\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Only update state if we have valid files to add\n\t\t\tif (validFiles.length > 0) {\n\t\t\t\t// Call the onFilesAdded callback with the newly added valid files\n\t\t\t\tonFilesAdded?.(validFiles);\n\n\t\t\t\tsetState((prev) => {\n\t\t\t\t\tconst newFiles = !multiple ? validFiles : [...prev.files, ...validFiles];\n\t\t\t\t\tonFilesChange?.(newFiles);\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t\tfiles: newFiles,\n\t\t\t\t\t\terrors\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t} else if (errors.length > 0) {\n\t\t\t\tsetState((prev) => ({\n\t\t\t\t\t...prev,\n\t\t\t\t\terrors\n\t\t\t\t}));\n\t\t\t}\n\n\t\t\t// Reset input value after handling files\n\t\t\tif (inputRef.current) {\n\t\t\t\tinputRef.current.value = \"\";\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tstate.files,\n\t\t\tmaxFiles,\n\t\t\tmultiple,\n\t\t\tmaxSize,\n\t\t\tvalidateFile,\n\t\t\tcreatePreview,\n\t\t\tgenerateUniqueId,\n\t\t\tclearFiles,\n\t\t\tonFilesChange,\n\t\t\tonFilesAdded,\n\t\t\terrorMessages\n\t\t]\n\t);\n\n\tconst removeFile = useCallback(\n\t\t(id: string) => {\n\t\t\tsetState((prev) => {\n\t\t\t\tconst fileToRemove = prev.files.find((file) => file.id === id);\n\t\t\t\tif (\n\t\t\t\t\tfileToRemove &&\n\t\t\t\t\tfileToRemove.preview &&\n\t\t\t\t\tfileToRemove.file instanceof File &&\n\t\t\t\t\tfileToRemove.file.type.startsWith(\"image/\")\n\t\t\t\t) {\n\t\t\t\t\tURL.revokeObjectURL(fileToRemove.preview);\n\t\t\t\t}\n\n\t\t\t\tconst newFiles = prev.files.filter((file) => file.id !== id);\n\t\t\t\tonFilesChange?.(newFiles);\n\n\t\t\t\treturn {\n\t\t\t\t\t...prev,\n\t\t\t\t\tfiles: newFiles,\n\t\t\t\t\terrors: []\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\t[onFilesChange]\n\t);\n\n\tconst clearErrors = useCallback(() => {\n\t\tsetState((prev) => ({\n\t\t\t...prev,\n\t\t\terrors: []\n\t\t}));\n\t}, []);\n\n\tconst handleDragEnter = useCallback((e: DragEvent<HTMLElement>) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tsetState((prev) => ({ ...prev, isDragging: true }));\n\t}, []);\n\n\tconst handleDragLeave = useCallback((e: DragEvent<HTMLElement>) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\n\t\tif (e.currentTarget.contains(e.relatedTarget as Node)) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetState((prev) => ({ ...prev, isDragging: false }));\n\t}, []);\n\n\tconst handleDragOver = useCallback((e: DragEvent<HTMLElement>) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}, []);\n\n\tconst handleDrop = useCallback(\n\t\t(e: DragEvent<HTMLElement>) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tsetState((prev) => ({ ...prev, isDragging: false }));\n\n\t\t\t// Don't process files if the input is disabled\n\t\t\tif (inputRef.current?.disabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n\t\t\t\t// In single file mode, only use the first file\n\t\t\t\tif (!multiple) {\n\t\t\t\t\tconst file = e.dataTransfer.files[0];\n\t\t\t\t\taddFiles([file]);\n\t\t\t\t} else {\n\t\t\t\t\taddFiles(e.dataTransfer.files);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[addFiles, multiple]\n\t);\n\n\tconst handleFileChange = useCallback(\n\t\t(e: ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (e.target.files && e.target.files.length > 0) {\n\t\t\t\taddFiles(e.target.files);\n\t\t\t}\n\t\t},\n\t\t[addFiles]\n\t);\n\n\tconst openFileDialog = useCallback(() => {\n\t\tif (inputRef.current) {\n\t\t\tinputRef.current.click();\n\t\t}\n\t}, []);\n\n\tconst getInputProps = useCallback(\n\t\t(props: InputHTMLAttributes<HTMLInputElement> = {}) => {\n\t\t\treturn {\n\t\t\t\t...props,\n\t\t\t\ttype: \"file\" as const,\n\t\t\t\tonChange: handleFileChange,\n\t\t\t\taccept: props.accept || accept,\n\t\t\t\tmultiple: props.multiple !== undefined ? props.multiple : multiple,\n\t\t\t\tref: inputRef\n\t\t\t};\n\t\t},\n\t\t[accept, multiple, handleFileChange]\n\t);\n\n\treturn [\n\t\tstate,\n\t\t{\n\t\t\taddFiles,\n\t\t\tremoveFile,\n\t\t\tclearFiles,\n\t\t\tclearErrors,\n\t\t\thandleDragEnter,\n\t\t\thandleDragLeave,\n\t\t\thandleDragOver,\n\t\t\thandleDrop,\n\t\t\thandleFileChange,\n\t\t\topenFileDialog,\n\t\t\tgetInputProps\n\t\t}\n\t];\n};\n"],"names":["defaultErrorMessages","fileName","maxSizeBytes","formatBytes","maxFiles","defaultErrorMessagesRu","useFileUpload","options","maxSize","accept","multiple","initialFiles","onFilesChange","onFilesAdded","customErrorMessages","errorMessages","useMemo","state","setState","useState","file","inputRef","useRef","validateFile","useCallback","acceptedTypes","type","fileType","fileExtension","baseType","createPreview","generateUniqueId","clearFiles","prev","newState","addFiles","newFiles","newFilesArray","errors","validFiles","existingFile","error","removeFile","id","fileToRemove","clearErrors","handleDragEnter","handleDragLeave","handleDragOver","handleDrop","handleFileChange","openFileDialog","getInputProps","props"],"mappings":"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"}
|
package/package.json
CHANGED
package/tailwind.preset.js
CHANGED
|
@@ -164,7 +164,7 @@ export default {
|
|
|
164
164
|
30: "hsl(var(--alpha-70))",
|
|
165
165
|
40: "hsl(var(--alpha-60))",
|
|
166
166
|
50: "hsl(var(--alpha-50))",
|
|
167
|
-
60: "hsl(var(--alpha-
|
|
167
|
+
60: "hsl(var(--alpha-40))",
|
|
168
168
|
70: "hsl(var(--alpha-30))",
|
|
169
169
|
80: "hsl(var(--alpha-20))",
|
|
170
170
|
90: "hsl(var(--alpha-10))",
|
|
@@ -178,7 +178,7 @@ export default {
|
|
|
178
178
|
30: "hsl(var(--alpha-high-70))",
|
|
179
179
|
40: "hsl(var(--alpha-high-60))",
|
|
180
180
|
50: "hsl(var(--alpha-high-50))",
|
|
181
|
-
60: "hsl(var(--alpha-high-
|
|
181
|
+
60: "hsl(var(--alpha-high-40))",
|
|
182
182
|
70: "hsl(var(--alpha-high-30))",
|
|
183
183
|
80: "hsl(var(--alpha-high-20))",
|
|
184
184
|
90: "hsl(var(--alpha-high-10))",
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { useMemo as A, useState as I, useRef as W, useCallback as n } from "react";
|
|
2
|
-
const T = (t, o = 2) => {
|
|
3
|
-
if (t === 0) return "0 Bytes";
|
|
4
|
-
const c = 1024, p = o < 0 ? 0 : o, a = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], v = Math.floor(Math.log(t) / Math.log(c));
|
|
5
|
-
return Number.parseFloat((t / Math.pow(c, v)).toFixed(p)) + a[v];
|
|
6
|
-
}, O = {
|
|
7
|
-
fileTooLarge: (t, o) => `File "${t}" exceeds the maximum size of ${T(o)}.`,
|
|
8
|
-
invalidFileType: (t) => `File "${t}" is not an accepted file type.`,
|
|
9
|
-
tooManyFiles: (t) => `You can only upload a maximum of ${t} files.`,
|
|
10
|
-
someFilesTooLarge: (t) => `Some files exceed the maximum size of ${T(t)}.`,
|
|
11
|
-
singleFileTooLarge: (t) => `File exceeds the maximum size of ${T(t)}.`
|
|
12
|
-
}, N = {
|
|
13
|
-
fileTooLarge: (t, o) => `Файл "${t}" превышает максимальный размер ${T(o)}`,
|
|
14
|
-
invalidFileType: (t) => `Файл "${t}" имеет недопустимый тип`,
|
|
15
|
-
tooManyFiles: (t) => `Можно загрузить максимум ${t} файлов`,
|
|
16
|
-
someFilesTooLarge: (t) => `Некоторые файлы превышают максимальный размер ${T(t)}`,
|
|
17
|
-
singleFileTooLarge: (t) => `Файл превышает максимальный размер ${T(t)}`
|
|
18
|
-
}, Y = (t = {}) => {
|
|
19
|
-
const {
|
|
20
|
-
maxFiles: o = 1 / 0,
|
|
21
|
-
maxSize: c = 1 / 0,
|
|
22
|
-
accept: p = "*",
|
|
23
|
-
multiple: a = !1,
|
|
24
|
-
initialFiles: v = [],
|
|
25
|
-
onFilesChange: m,
|
|
26
|
-
onFilesAdded: M,
|
|
27
|
-
errorMessages: w
|
|
28
|
-
} = t, d = A(() => ({ ...O, ...w }), [w]), [y, f] = I({
|
|
29
|
-
files: v.map((e) => ({
|
|
30
|
-
file: e,
|
|
31
|
-
id: e.id,
|
|
32
|
-
preview: e.url
|
|
33
|
-
})),
|
|
34
|
-
isDragging: !1,
|
|
35
|
-
errors: []
|
|
36
|
-
}), u = W(null), x = n(
|
|
37
|
-
(e) => {
|
|
38
|
-
const r = (e instanceof File, e.name);
|
|
39
|
-
if (e.size > c)
|
|
40
|
-
return d.fileTooLarge(r, c);
|
|
41
|
-
if (p !== "*") {
|
|
42
|
-
const i = p.split(",").map((g) => g.trim()), l = e instanceof File ? e.type || "" : e.type, s = `.${r.split(".").pop()}`;
|
|
43
|
-
if (!i.some((g) => {
|
|
44
|
-
if (g.startsWith("."))
|
|
45
|
-
return s.toLowerCase() === g.toLowerCase();
|
|
46
|
-
if (g.endsWith("/*")) {
|
|
47
|
-
const L = g.split("/")[0];
|
|
48
|
-
return l.startsWith(`${L}/`);
|
|
49
|
-
}
|
|
50
|
-
return l === g;
|
|
51
|
-
}))
|
|
52
|
-
return d.invalidFileType(r);
|
|
53
|
-
}
|
|
54
|
-
return null;
|
|
55
|
-
},
|
|
56
|
-
[p, c, d]
|
|
57
|
-
), B = n((e) => e instanceof File ? URL.createObjectURL(e) : e.url, []), R = n((e) => e instanceof File ? `${e.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}` : e.id, []), $ = n(() => {
|
|
58
|
-
f((e) => {
|
|
59
|
-
e.files.forEach((i) => {
|
|
60
|
-
i.preview && i.file instanceof File && i.file.type.startsWith("image/") && URL.revokeObjectURL(i.preview);
|
|
61
|
-
}), u.current && (u.current.value = "");
|
|
62
|
-
const r = {
|
|
63
|
-
...e,
|
|
64
|
-
files: [],
|
|
65
|
-
errors: []
|
|
66
|
-
};
|
|
67
|
-
return m?.(r.files), r;
|
|
68
|
-
});
|
|
69
|
-
}, [m]), F = n(
|
|
70
|
-
(e) => {
|
|
71
|
-
if (!e || e.length === 0) return;
|
|
72
|
-
const r = Array.from(e), i = [];
|
|
73
|
-
if (f((s) => ({ ...s, errors: [] })), a || $(), a && o !== 1 / 0 && y.files.length + r.length > o) {
|
|
74
|
-
i.push(d.tooManyFiles(o)), f((s) => ({ ...s, errors: i }));
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
const l = [];
|
|
78
|
-
r.forEach((s) => {
|
|
79
|
-
if (a && y.files.some(
|
|
80
|
-
(L) => L.file.name === s.name && L.file.size === s.size
|
|
81
|
-
))
|
|
82
|
-
return;
|
|
83
|
-
if (s.size > c) {
|
|
84
|
-
i.push(
|
|
85
|
-
a ? d.someFilesTooLarge(c) : d.singleFileTooLarge(c)
|
|
86
|
-
);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const h = x(s);
|
|
90
|
-
h ? i.push(h) : l.push({
|
|
91
|
-
file: s,
|
|
92
|
-
id: R(s),
|
|
93
|
-
preview: B(s)
|
|
94
|
-
});
|
|
95
|
-
}), l.length > 0 ? (M?.(l), f((s) => {
|
|
96
|
-
const h = a ? [...s.files, ...l] : l;
|
|
97
|
-
return m?.(h), {
|
|
98
|
-
...s,
|
|
99
|
-
files: h,
|
|
100
|
-
errors: i
|
|
101
|
-
};
|
|
102
|
-
})) : i.length > 0 && f((s) => ({
|
|
103
|
-
...s,
|
|
104
|
-
errors: i
|
|
105
|
-
})), u.current && (u.current.value = "");
|
|
106
|
-
},
|
|
107
|
-
[
|
|
108
|
-
y.files,
|
|
109
|
-
o,
|
|
110
|
-
a,
|
|
111
|
-
c,
|
|
112
|
-
x,
|
|
113
|
-
B,
|
|
114
|
-
R,
|
|
115
|
-
$,
|
|
116
|
-
m,
|
|
117
|
-
M,
|
|
118
|
-
d
|
|
119
|
-
]
|
|
120
|
-
), z = n(
|
|
121
|
-
(e) => {
|
|
122
|
-
f((r) => {
|
|
123
|
-
const i = r.files.find((s) => s.id === e);
|
|
124
|
-
i && i.preview && i.file instanceof File && i.file.type.startsWith("image/") && URL.revokeObjectURL(i.preview);
|
|
125
|
-
const l = r.files.filter((s) => s.id !== e);
|
|
126
|
-
return m?.(l), {
|
|
127
|
-
...r,
|
|
128
|
-
files: l,
|
|
129
|
-
errors: []
|
|
130
|
-
};
|
|
131
|
-
});
|
|
132
|
-
},
|
|
133
|
-
[m]
|
|
134
|
-
), E = n(() => {
|
|
135
|
-
f((e) => ({
|
|
136
|
-
...e,
|
|
137
|
-
errors: []
|
|
138
|
-
}));
|
|
139
|
-
}, []), U = n((e) => {
|
|
140
|
-
e.preventDefault(), e.stopPropagation(), f((r) => ({ ...r, isDragging: !0 }));
|
|
141
|
-
}, []), P = n((e) => {
|
|
142
|
-
e.preventDefault(), e.stopPropagation(), !e.currentTarget.contains(e.relatedTarget) && f((r) => ({ ...r, isDragging: !1 }));
|
|
143
|
-
}, []), b = n((e) => {
|
|
144
|
-
e.preventDefault(), e.stopPropagation();
|
|
145
|
-
}, []), C = n(
|
|
146
|
-
(e) => {
|
|
147
|
-
if (e.preventDefault(), e.stopPropagation(), f((r) => ({ ...r, isDragging: !1 })), !u.current?.disabled && e.dataTransfer.files && e.dataTransfer.files.length > 0)
|
|
148
|
-
if (a)
|
|
149
|
-
F(e.dataTransfer.files);
|
|
150
|
-
else {
|
|
151
|
-
const r = e.dataTransfer.files[0];
|
|
152
|
-
F([r]);
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
[F, a]
|
|
156
|
-
), D = n(
|
|
157
|
-
(e) => {
|
|
158
|
-
e.target.files && e.target.files.length > 0 && F(e.target.files);
|
|
159
|
-
},
|
|
160
|
-
[F]
|
|
161
|
-
), S = n(() => {
|
|
162
|
-
u.current && u.current.click();
|
|
163
|
-
}, []), k = n(
|
|
164
|
-
(e = {}) => ({
|
|
165
|
-
...e,
|
|
166
|
-
type: "file",
|
|
167
|
-
onChange: D,
|
|
168
|
-
accept: e.accept || p,
|
|
169
|
-
multiple: e.multiple !== void 0 ? e.multiple : a,
|
|
170
|
-
ref: u
|
|
171
|
-
}),
|
|
172
|
-
[p, a, D]
|
|
173
|
-
);
|
|
174
|
-
return [
|
|
175
|
-
y,
|
|
176
|
-
{
|
|
177
|
-
addFiles: F,
|
|
178
|
-
removeFile: z,
|
|
179
|
-
clearFiles: $,
|
|
180
|
-
clearErrors: E,
|
|
181
|
-
handleDragEnter: U,
|
|
182
|
-
handleDragLeave: P,
|
|
183
|
-
handleDragOver: b,
|
|
184
|
-
handleDrop: C,
|
|
185
|
-
handleFileChange: D,
|
|
186
|
-
openFileDialog: S,
|
|
187
|
-
getInputProps: k
|
|
188
|
-
}
|
|
189
|
-
];
|
|
190
|
-
};
|
|
191
|
-
export {
|
|
192
|
-
N as a,
|
|
193
|
-
O as d,
|
|
194
|
-
T as f,
|
|
195
|
-
Y as u
|
|
196
|
-
};
|
|
197
|
-
//# sourceMappingURL=useFileUpload-iDag0iqM.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useFileUpload-iDag0iqM.js","sources":["../src/lib/utils/file/formatBytes.ts","../src/hooks/use-file-upload/errorMessages.ts","../src/hooks/use-file-upload/useFileUpload.ts"],"sourcesContent":["// Helper function to format bytes to human-readable format\nexport const formatBytes = (bytes: number, decimals = 2): string => {\n\tif (bytes === 0) return \"0 Bytes\";\n\n\tconst k = 1024;\n\tconst dm = decimals < 0 ? 0 : decimals;\n\tconst sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\n\treturn Number.parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + sizes[i];\n};\n","import { formatBytes } from \"@/lib/utils/file/formatBytes\";\n\n/**\n * Интерфейс для кастомизации сообщений об ошибках в useFileUpload\n */\nexport interface FileUploadErrorMessages {\n\t/**\n\t * Сообщение когда файл превышает максимальный размер\n\t * @param fileName - имя файла\n\t * @param maxSizeBytes - максимальный размер в байтах\n\t */\n\tfileTooLarge?: (fileName: string, maxSizeBytes: number) => string;\n\n\t/**\n\t * Сообщение когда тип файла не разрешен\n\t * @param fileName - имя файла\n\t */\n\tinvalidFileType?: (fileName: string) => string;\n\n\t/**\n\t * Сообщение когда превышено максимальное количество файлов\n\t * @param maxFiles - максимальное количество файлов\n\t */\n\ttooManyFiles?: (maxFiles: number) => string;\n\n\t/**\n\t * Сообщение когда некоторые файлы превышают максимальный размер (для множественной загрузки)\n\t * @param maxSizeBytes - максимальный размер в байтах\n\t */\n\tsomeFilesTooLarge?: (maxSizeBytes: number) => string;\n\n\t/**\n\t * Сообщение когда файл превышает максимальный размер (для одиночной загрузки)\n\t * @param maxSizeBytes - максимальный размер в байтах\n\t */\n\tsingleFileTooLarge?: (maxSizeBytes: number) => string;\n}\n\n/**\n * Сообщения об ошибках по умолчанию\n */\nexport const defaultErrorMessages: Required<FileUploadErrorMessages> = {\n\tfileTooLarge: (fileName, maxSizeBytes) =>\n\t\t`File \"${fileName}\" exceeds the maximum size of ${formatBytes(maxSizeBytes)}.`,\n\tinvalidFileType: (fileName) => `File \"${fileName}\" is not an accepted file type.`,\n\ttooManyFiles: (maxFiles) => `You can only upload a maximum of ${maxFiles} files.`,\n\tsomeFilesTooLarge: (maxSizeBytes) => `Some files exceed the maximum size of ${formatBytes(maxSizeBytes)}.`,\n\tsingleFileTooLarge: (maxSizeBytes) => `File exceeds the maximum size of ${formatBytes(maxSizeBytes)}.`\n};\n\n/**\n * Сообщения об ошибках на русском языке\n */\nexport const defaultErrorMessagesRu: Required<FileUploadErrorMessages> = {\n\tfileTooLarge: (fileName, maxSizeBytes) =>\n\t\t`Файл \"${fileName}\" превышает максимальный размер ${formatBytes(maxSizeBytes)}`,\n\tinvalidFileType: (fileName) => `Файл \"${fileName}\" имеет недопустимый тип`,\n\ttooManyFiles: (maxFiles) => `Можно загрузить максимум ${maxFiles} файлов`,\n\tsomeFilesTooLarge: (maxSizeBytes) => `Некоторые файлы превышают максимальный размер ${formatBytes(maxSizeBytes)}`,\n\tsingleFileTooLarge: (maxSizeBytes) => `Файл превышает максимальный размер ${formatBytes(maxSizeBytes)}`\n};\n","import {\n\tuseCallback,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n\ttype ChangeEvent,\n\ttype DragEvent,\n\ttype InputHTMLAttributes\n} from \"react\";\nimport { defaultErrorMessages, type FileUploadErrorMessages } from \"./errorMessages\";\n\nexport type FileData = {\n\tname: string;\n\tsize: number;\n\ttype: string;\n\tid?: string;\n};\n\nexport type FileMetadata = FileData & {\n\turl: string;\n\tid: string;\n};\n\nexport type FileValue = File | FileData;\n\nexport type FileWithPreview = {\n\tfile: FileValue;\n\tid: string;\n\tpreview?: string;\n};\n\n/**\n * Ограничения для загрузки файлов\n */\nexport type FileUploadConstraints = {\n\t/**\n\t * Максимальное количество файлов\n\t * Используется только когда multiple=true\n\t * @default Infinity\n\t */\n\tmaxFiles?: number;\n\n\t/**\n\t * Максимальный размер файла в байтах\n\t * @default Infinity\n\t */\n\tmaxSize?: number;\n\n\t/**\n\t * Допустимые типы файлов (строка MIME-типов или расширений через запятую)\n\t * @example \"image/jpeg,image/png,.pdf,.doc\"\n\t * @example \"*.jpg,*.png\"\n\t * @example \"image/*\"\n\t * @default \"*\"\n\t */\n\taccept?: string;\n\n\t/**\n\t * Разрешить выбор нескольких файлов\n\t * @default false\n\t */\n\tmultiple?: boolean;\n};\n\nexport type FileUploadOptions = FileUploadConstraints & {\n\tinitialFiles?: FileMetadata[];\n\tonFilesChange?: (files: FileWithPreview[]) => void;\n\tonFilesAdded?: (addedFiles: FileWithPreview[]) => void;\n\t/**\n\t * Кастомные сообщения об ошибках\n\t * Можно переопределить только нужные сообщения\n\t */\n\terrorMessages?: Partial<FileUploadErrorMessages>;\n};\n\nexport type FileUploadState = {\n\tfiles: FileWithPreview[];\n\tisDragging: boolean;\n\terrors: string[];\n};\n\nexport type FileUploadActions = {\n\taddFiles: (files: FileList | File[]) => void;\n\tremoveFile: (id: string) => void;\n\tclearFiles: () => void;\n\tclearErrors: () => void;\n\thandleDragEnter: (e: DragEvent<HTMLElement>) => void;\n\thandleDragLeave: (e: DragEvent<HTMLElement>) => void;\n\thandleDragOver: (e: DragEvent<HTMLElement>) => void;\n\thandleDrop: (e: DragEvent<HTMLElement>) => void;\n\thandleFileChange: (e: ChangeEvent<HTMLInputElement>) => void;\n\topenFileDialog: () => void;\n\tgetInputProps: (props?: InputHTMLAttributes<HTMLInputElement>) => InputHTMLAttributes<HTMLInputElement> & {\n\t\tref: React.Ref<HTMLInputElement>;\n\t};\n};\n\n/** Хук был взять из библиотеки originui.\n * Код можно посмотреть по ссылке: https://github.com/origin-space/originui/blob/main/docs/use-file-upload.md\n */\nexport const useFileUpload = (options: FileUploadOptions = {}): [FileUploadState, FileUploadActions] => {\n\tconst {\n\t\tmaxFiles = Infinity,\n\t\tmaxSize = Infinity,\n\t\taccept = \"*\",\n\t\tmultiple = false,\n\t\tinitialFiles = [],\n\t\tonFilesChange,\n\t\tonFilesAdded,\n\t\terrorMessages: customErrorMessages\n\t} = options;\n\n\t// Объединяем дефолтные и кастомные сообщения\n\tconst errorMessages = useMemo(() => ({ ...defaultErrorMessages, ...customErrorMessages }), [customErrorMessages]);\n\n\tconst [state, setState] = useState<FileUploadState>({\n\t\tfiles: initialFiles.map((file) => ({\n\t\t\tfile,\n\t\t\tid: file.id,\n\t\t\tpreview: file.url\n\t\t})),\n\t\tisDragging: false,\n\t\terrors: []\n\t});\n\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\n\tconst validateFile = useCallback(\n\t\t(file: FileValue): string | null => {\n\t\t\tconst fileName = file instanceof File ? file.name : file.name;\n\n\t\t\tif (file.size > maxSize) {\n\t\t\t\treturn errorMessages.fileTooLarge(fileName, maxSize);\n\t\t\t}\n\n\t\t\tif (accept !== \"*\") {\n\t\t\t\tconst acceptedTypes = accept.split(\",\").map((type) => type.trim());\n\t\t\t\tconst fileType = file instanceof File ? file.type || \"\" : file.type;\n\t\t\t\tconst fileExtension = `.${fileName.split(\".\").pop()}`;\n\n\t\t\t\tconst isAccepted = acceptedTypes.some((type) => {\n\t\t\t\t\tif (type.startsWith(\".\")) {\n\t\t\t\t\t\treturn fileExtension.toLowerCase() === type.toLowerCase();\n\t\t\t\t\t}\n\t\t\t\t\tif (type.endsWith(\"/*\")) {\n\t\t\t\t\t\tconst baseType = type.split(\"/\")[0];\n\t\t\t\t\t\treturn fileType.startsWith(`${baseType}/`);\n\t\t\t\t\t}\n\t\t\t\t\treturn fileType === type;\n\t\t\t\t});\n\n\t\t\t\tif (!isAccepted) {\n\t\t\t\t\treturn errorMessages.invalidFileType(fileName);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\t\t[accept, maxSize, errorMessages]\n\t);\n\n\tconst createPreview = useCallback((file: File | FileMetadata): string | undefined => {\n\t\tif (file instanceof File) {\n\t\t\treturn URL.createObjectURL(file);\n\t\t}\n\t\treturn file.url;\n\t}, []);\n\n\tconst generateUniqueId = useCallback((file: File | FileMetadata): string => {\n\t\tif (file instanceof File) {\n\t\t\treturn `${file.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n\t\t}\n\t\treturn file.id;\n\t}, []);\n\n\tconst clearFiles = useCallback(() => {\n\t\tsetState((prev) => {\n\t\t\t// Clean up object URLs\n\t\t\tprev.files.forEach((file) => {\n\t\t\t\tif (file.preview && file.file instanceof File && file.file.type.startsWith(\"image/\")) {\n\t\t\t\t\tURL.revokeObjectURL(file.preview);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (inputRef.current) {\n\t\t\t\tinputRef.current.value = \"\";\n\t\t\t}\n\n\t\t\tconst newState = {\n\t\t\t\t...prev,\n\t\t\t\tfiles: [],\n\t\t\t\terrors: []\n\t\t\t};\n\n\t\t\tonFilesChange?.(newState.files);\n\t\t\treturn newState;\n\t\t});\n\t}, [onFilesChange]);\n\n\tconst addFiles = useCallback(\n\t\t(newFiles: FileList | File[]) => {\n\t\t\tif (!newFiles || newFiles.length === 0) return;\n\n\t\t\tconst newFilesArray = Array.from(newFiles);\n\t\t\tconst errors: string[] = [];\n\n\t\t\t// Clear existing errors when new files are uploaded\n\t\t\tsetState((prev) => ({ ...prev, errors: [] }));\n\n\t\t\t// In single file mode, clear existing files first\n\t\t\tif (!multiple) {\n\t\t\t\tclearFiles();\n\t\t\t}\n\n\t\t\t// Check if adding these files would exceed maxFiles (only in multiple mode)\n\t\t\tif (multiple && maxFiles !== Infinity && state.files.length + newFilesArray.length > maxFiles) {\n\t\t\t\terrors.push(errorMessages.tooManyFiles(maxFiles));\n\t\t\t\tsetState((prev) => ({ ...prev, errors }));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst validFiles: FileWithPreview[] = [];\n\n\t\t\tnewFilesArray.forEach((file) => {\n\t\t\t\t// Only check for duplicates if multiple files are allowed\n\t\t\t\tif (multiple) {\n\t\t\t\t\tconst isDuplicate = state.files.some(\n\t\t\t\t\t\t(existingFile) => existingFile.file.name === file.name && existingFile.file.size === file.size\n\t\t\t\t\t);\n\n\t\t\t\t\t// Skip duplicate files silently\n\t\t\t\t\tif (isDuplicate) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check file size\n\t\t\t\tif (file.size > maxSize) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\tmultiple ? errorMessages.someFilesTooLarge(maxSize) : errorMessages.singleFileTooLarge(maxSize)\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst error = validateFile(file);\n\t\t\t\tif (error) {\n\t\t\t\t\terrors.push(error);\n\t\t\t\t} else {\n\t\t\t\t\tvalidFiles.push({\n\t\t\t\t\t\tfile,\n\t\t\t\t\t\tid: generateUniqueId(file),\n\t\t\t\t\t\tpreview: createPreview(file)\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Only update state if we have valid files to add\n\t\t\tif (validFiles.length > 0) {\n\t\t\t\t// Call the onFilesAdded callback with the newly added valid files\n\t\t\t\tonFilesAdded?.(validFiles);\n\n\t\t\t\tsetState((prev) => {\n\t\t\t\t\tconst newFiles = !multiple ? validFiles : [...prev.files, ...validFiles];\n\t\t\t\t\tonFilesChange?.(newFiles);\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t\tfiles: newFiles,\n\t\t\t\t\t\terrors\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t} else if (errors.length > 0) {\n\t\t\t\tsetState((prev) => ({\n\t\t\t\t\t...prev,\n\t\t\t\t\terrors\n\t\t\t\t}));\n\t\t\t}\n\n\t\t\t// Reset input value after handling files\n\t\t\tif (inputRef.current) {\n\t\t\t\tinputRef.current.value = \"\";\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tstate.files,\n\t\t\tmaxFiles,\n\t\t\tmultiple,\n\t\t\tmaxSize,\n\t\t\tvalidateFile,\n\t\t\tcreatePreview,\n\t\t\tgenerateUniqueId,\n\t\t\tclearFiles,\n\t\t\tonFilesChange,\n\t\t\tonFilesAdded,\n\t\t\terrorMessages\n\t\t]\n\t);\n\n\tconst removeFile = useCallback(\n\t\t(id: string) => {\n\t\t\tsetState((prev) => {\n\t\t\t\tconst fileToRemove = prev.files.find((file) => file.id === id);\n\t\t\t\tif (\n\t\t\t\t\tfileToRemove &&\n\t\t\t\t\tfileToRemove.preview &&\n\t\t\t\t\tfileToRemove.file instanceof File &&\n\t\t\t\t\tfileToRemove.file.type.startsWith(\"image/\")\n\t\t\t\t) {\n\t\t\t\t\tURL.revokeObjectURL(fileToRemove.preview);\n\t\t\t\t}\n\n\t\t\t\tconst newFiles = prev.files.filter((file) => file.id !== id);\n\t\t\t\tonFilesChange?.(newFiles);\n\n\t\t\t\treturn {\n\t\t\t\t\t...prev,\n\t\t\t\t\tfiles: newFiles,\n\t\t\t\t\terrors: []\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\t[onFilesChange]\n\t);\n\n\tconst clearErrors = useCallback(() => {\n\t\tsetState((prev) => ({\n\t\t\t...prev,\n\t\t\terrors: []\n\t\t}));\n\t}, []);\n\n\tconst handleDragEnter = useCallback((e: DragEvent<HTMLElement>) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tsetState((prev) => ({ ...prev, isDragging: true }));\n\t}, []);\n\n\tconst handleDragLeave = useCallback((e: DragEvent<HTMLElement>) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\n\t\tif (e.currentTarget.contains(e.relatedTarget as Node)) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetState((prev) => ({ ...prev, isDragging: false }));\n\t}, []);\n\n\tconst handleDragOver = useCallback((e: DragEvent<HTMLElement>) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}, []);\n\n\tconst handleDrop = useCallback(\n\t\t(e: DragEvent<HTMLElement>) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tsetState((prev) => ({ ...prev, isDragging: false }));\n\n\t\t\t// Don't process files if the input is disabled\n\t\t\tif (inputRef.current?.disabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n\t\t\t\t// In single file mode, only use the first file\n\t\t\t\tif (!multiple) {\n\t\t\t\t\tconst file = e.dataTransfer.files[0];\n\t\t\t\t\taddFiles([file]);\n\t\t\t\t} else {\n\t\t\t\t\taddFiles(e.dataTransfer.files);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[addFiles, multiple]\n\t);\n\n\tconst handleFileChange = useCallback(\n\t\t(e: ChangeEvent<HTMLInputElement>) => {\n\t\t\tif (e.target.files && e.target.files.length > 0) {\n\t\t\t\taddFiles(e.target.files);\n\t\t\t}\n\t\t},\n\t\t[addFiles]\n\t);\n\n\tconst openFileDialog = useCallback(() => {\n\t\tif (inputRef.current) {\n\t\t\tinputRef.current.click();\n\t\t}\n\t}, []);\n\n\tconst getInputProps = useCallback(\n\t\t(props: InputHTMLAttributes<HTMLInputElement> = {}) => {\n\t\t\treturn {\n\t\t\t\t...props,\n\t\t\t\ttype: \"file\" as const,\n\t\t\t\tonChange: handleFileChange,\n\t\t\t\taccept: props.accept || accept,\n\t\t\t\tmultiple: props.multiple !== undefined ? props.multiple : multiple,\n\t\t\t\tref: inputRef\n\t\t\t};\n\t\t},\n\t\t[accept, multiple, handleFileChange]\n\t);\n\n\treturn [\n\t\tstate,\n\t\t{\n\t\t\taddFiles,\n\t\t\tremoveFile,\n\t\t\tclearFiles,\n\t\t\tclearErrors,\n\t\t\thandleDragEnter,\n\t\t\thandleDragLeave,\n\t\t\thandleDragOver,\n\t\t\thandleDrop,\n\t\t\thandleFileChange,\n\t\t\topenFileDialog,\n\t\t\tgetInputProps\n\t\t}\n\t];\n};\n"],"names":["formatBytes","bytes","decimals","k","dm","sizes","i","defaultErrorMessages","fileName","maxSizeBytes","maxFiles","defaultErrorMessagesRu","useFileUpload","options","maxSize","accept","multiple","initialFiles","onFilesChange","onFilesAdded","customErrorMessages","errorMessages","useMemo","state","setState","useState","file","inputRef","useRef","validateFile","useCallback","acceptedTypes","type","fileType","fileExtension","baseType","createPreview","generateUniqueId","clearFiles","prev","newState","addFiles","newFiles","newFilesArray","errors","validFiles","existingFile","error","removeFile","id","fileToRemove","clearErrors","handleDragEnter","handleDragLeave","handleDragOver","handleDrop","handleFileChange","openFileDialog","getInputProps","props"],"mappings":"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"}
|