ar-design 0.2.68 → 0.2.70
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/assets/css/components/form/upload/styles.css +69 -35
- package/dist/components/form/upload/Props.d.ts +3 -2
- package/dist/components/form/upload/index.js +90 -47
- package/dist/components/icons/Compiler.js +5 -0
- package/dist/components/icons/index.js +1 -1
- package/dist/libs/core/service/Api.d.ts +4 -1
- package/dist/libs/core/service/Api.js +4 -2
- package/dist/libs/core/service/index.js +2 -2
- package/package.json +1 -1
|
@@ -17,55 +17,89 @@
|
|
|
17
17
|
font-size: 0.15rem;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
.ar-upload-button > .
|
|
20
|
+
.ar-upload-button > .button {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: 1rem;
|
|
26
|
+
padding: 1rem 0;
|
|
27
|
+
border: dashed 1px var(--gray-300);
|
|
28
|
+
border-radius: var(--border-radius-sm);
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
user-select: none;
|
|
31
|
+
}
|
|
32
|
+
.ar-upload-button > .button:has(> img) {
|
|
33
|
+
padding: 0;
|
|
34
|
+
border: none;
|
|
35
|
+
overflow: hidden;
|
|
36
|
+
}
|
|
37
|
+
.ar-upload-button > .button > img {
|
|
21
38
|
width: 100%;
|
|
22
|
-
|
|
39
|
+
height: 200px;
|
|
40
|
+
object-fit: fill;
|
|
41
|
+
object-position: top;
|
|
23
42
|
}
|
|
24
|
-
.ar-upload-button > .
|
|
43
|
+
.ar-upload-button > .button > .information {
|
|
25
44
|
display: flex;
|
|
26
45
|
flex-direction: column;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
position: relative;
|
|
31
|
-
border-bottom: solid 1px var(--gray-200);
|
|
46
|
+
justify-content: center;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 0.5rem;
|
|
32
49
|
}
|
|
33
|
-
.ar-upload-button > .
|
|
50
|
+
.ar-upload-button > .button > .information > .properies {
|
|
34
51
|
display: flex;
|
|
52
|
+
flex-direction: row;
|
|
53
|
+
gap: 0.5rem;
|
|
54
|
+
font-size: 0.85rem;
|
|
55
|
+
}
|
|
56
|
+
.ar-upload-button > .button > .information > .properies > .max-size {
|
|
57
|
+
color: var(--gray-500);
|
|
58
|
+
}
|
|
59
|
+
.ar-upload-button > .button > .information > .properies > .allow-types {
|
|
60
|
+
color: var(--gray-500);
|
|
35
61
|
}
|
|
36
|
-
|
|
37
|
-
|
|
62
|
+
|
|
63
|
+
.ar-upload-button > .ar-upload-files {
|
|
64
|
+
width: 100%;
|
|
65
|
+
transition: top 250ms ease-in-out;
|
|
38
66
|
}
|
|
39
|
-
.ar-upload-button > .ar-upload-files > ul
|
|
67
|
+
.ar-upload-button > .ar-upload-files > ul {
|
|
68
|
+
list-style: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.ar-upload-button > .ar-upload-files > ul > li > .file,
|
|
72
|
+
.ar-upload-button > .ar-upload-files > .file {
|
|
40
73
|
display: flex;
|
|
41
74
|
flex-direction: row;
|
|
42
75
|
justify-content: space-between;
|
|
43
76
|
align-items: center;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
padding: 0
|
|
77
|
+
background-color: var(--gray-200);
|
|
78
|
+
margin-top: 0.5rem;
|
|
79
|
+
padding: 0.5rem;
|
|
80
|
+
border-radius: var(--border-radius-sm);
|
|
47
81
|
}
|
|
48
|
-
.ar-upload-button > .ar-upload-files > ul > li .
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.ar-upload-button > .ar-upload-files >
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.ar-upload-button > .ar-upload-files >
|
|
60
|
-
background-color:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
color: rgba(var(--danger-rgb), 0.5);
|
|
82
|
+
.ar-upload-button > .ar-upload-files > ul > li > .file > .information,
|
|
83
|
+
.ar-upload-button > .ar-upload-files > .file > .information {
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: row;
|
|
86
|
+
gap: 0.5rem;
|
|
87
|
+
}
|
|
88
|
+
.ar-upload-button > .ar-upload-files > ul > li > .file > .information > span,
|
|
89
|
+
.ar-upload-button > .ar-upload-files > .file > .information > span {
|
|
90
|
+
display: inline-block;
|
|
91
|
+
}
|
|
92
|
+
.ar-upload-button > .ar-upload-files > ul > li > .file > .information > span:last-child,
|
|
93
|
+
.ar-upload-button > .ar-upload-files > .file > .information > span:last-child {
|
|
94
|
+
background-color: var(--primary);
|
|
95
|
+
padding: 0 0.25rem;
|
|
96
|
+
border-radius: var(--border-radius-sm);
|
|
97
|
+
color: var(--white);
|
|
65
98
|
font-size: 0.75rem;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
99
|
+
line-height: 2;
|
|
100
|
+
}
|
|
101
|
+
.ar-upload-button > .ar-upload-files > ul > li > .file > .delete,
|
|
102
|
+
.ar-upload-button > .ar-upload-files > .file > .delete {
|
|
69
103
|
cursor: pointer;
|
|
70
104
|
}
|
|
71
105
|
|
|
@@ -32,7 +32,7 @@ interface IMultiple {
|
|
|
32
32
|
* />
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
|
-
onChange: (formData: FormData, files: File[], isInvalidFileExist: boolean) => void;
|
|
35
|
+
onChange: (formData: FormData, files: File[], base64: string[], isInvalidFileExist: boolean) => void;
|
|
36
36
|
/**
|
|
37
37
|
* Çoklu dosya seçiminin aktif olduğunu belirtir.
|
|
38
38
|
*
|
|
@@ -66,7 +66,7 @@ interface ISingle {
|
|
|
66
66
|
* <Upload onChange={(formData, file) => console.log(file)} />
|
|
67
67
|
* ```
|
|
68
68
|
*/
|
|
69
|
-
onChange: (formData: FormData | undefined, files: File | null) => void;
|
|
69
|
+
onChange: (formData: FormData | undefined, files: File | null, base64: string) => void;
|
|
70
70
|
/**
|
|
71
71
|
* Çoklu dosya seçiminin devre dışı olduğunu belirtir.
|
|
72
72
|
*
|
|
@@ -98,6 +98,7 @@ type Props = {
|
|
|
98
98
|
* ```
|
|
99
99
|
*/
|
|
100
100
|
allowedTypes?: AllowedTypes[];
|
|
101
|
+
uploadType?: "image" | "application-file";
|
|
101
102
|
/**
|
|
102
103
|
* Kabul edilen maksimum dosya boyutu (byte cinsinden).
|
|
103
104
|
*
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
import "../../../assets/css/components/form/upload/styles.css";
|
|
3
|
-
import { ARIcon } from "../../icons";
|
|
4
|
-
import Button from "../button";
|
|
5
3
|
import Tooltip from "../../feedback/tooltip";
|
|
6
|
-
|
|
4
|
+
import { ARIcon } from "../../icons";
|
|
5
|
+
const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-file", maxSize, multiple, }) => {
|
|
7
6
|
// refs
|
|
8
7
|
const _firstLoad = useRef(false);
|
|
9
8
|
const _input = useRef(null);
|
|
@@ -11,8 +10,9 @@ const Upload = ({ text, file, onChange, allowedTypes, maxSize, multiple }) => {
|
|
|
11
10
|
// refs -> File Data
|
|
12
11
|
const _validationErrors = useRef([]);
|
|
13
12
|
// states
|
|
14
|
-
const [selectedFiles, setSelectedFiles] = useState([]);
|
|
15
13
|
const [selectedFile, setSelectedFile] = useState(undefined);
|
|
14
|
+
const [selectedFileBase64, setSelectedFileBase64] = useState(undefined);
|
|
15
|
+
const [selectedFiles, setSelectedFiles] = useState([]);
|
|
16
16
|
const [validationErrors, setValidationErrors] = useState([]);
|
|
17
17
|
// methods
|
|
18
18
|
const handleFileChange = (files) => {
|
|
@@ -39,6 +39,10 @@ const Upload = ({ text, file, onChange, allowedTypes, maxSize, multiple }) => {
|
|
|
39
39
|
return newList;
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
+
else {
|
|
43
|
+
setSelectedFile(undefined);
|
|
44
|
+
setSelectedFileBase64(undefined);
|
|
45
|
+
}
|
|
42
46
|
};
|
|
43
47
|
const handleValidationFile = (file) => {
|
|
44
48
|
const newErrors = [];
|
|
@@ -49,7 +53,7 @@ const Upload = ({ text, file, onChange, allowedTypes, maxSize, multiple }) => {
|
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
if (maxSize) {
|
|
52
|
-
const _maxSize = maxSize * 1024 * 1024; //
|
|
56
|
+
const _maxSize = maxSize * 1024 * 1024; // MB
|
|
53
57
|
if (file.size > _maxSize) {
|
|
54
58
|
newErrors.push({ [file.name]: "Dosya boyutu çok büyük." });
|
|
55
59
|
_validationErrors.current.push(file.name);
|
|
@@ -57,36 +61,56 @@ const Upload = ({ text, file, onChange, allowedTypes, maxSize, multiple }) => {
|
|
|
57
61
|
}
|
|
58
62
|
setValidationErrors((prev) => [...prev, ...newErrors]);
|
|
59
63
|
};
|
|
64
|
+
function handleFileToBase64(file) {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const reader = new FileReader();
|
|
67
|
+
reader.onload = () => {
|
|
68
|
+
if (reader.result && typeof reader.result === "string") {
|
|
69
|
+
resolve(reader.result);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
reject(new Error("Failed to read the file"));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
reader.onerror = reject;
|
|
76
|
+
reader.readAsDataURL(file);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
60
79
|
// useEffects
|
|
61
80
|
useEffect(() => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
selectedFiles.forEach((f) => dataTransfer.items.add(f));
|
|
73
|
-
_input.current.files = dataTransfer.files;
|
|
74
|
-
// Geçerli olan dosyalar alındı...
|
|
75
|
-
const validFiles = [...selectedFiles.filter((x) => !inValidFiles.includes(x.name))];
|
|
76
|
-
validFiles.forEach((f) => fileFormData.append("file", f));
|
|
77
|
-
onChange(fileFormData, validFiles, _validationErrors.current.length === 0);
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
if (selectedFile) {
|
|
81
|
-
handleValidationFile(selectedFile);
|
|
82
|
-
fileFormData.append("file", selectedFile);
|
|
83
|
-
onChange(fileFormData, selectedFile);
|
|
81
|
+
(async () => {
|
|
82
|
+
const dataTransfer = new DataTransfer();
|
|
83
|
+
const fileFormData = new FormData();
|
|
84
|
+
setValidationErrors([]);
|
|
85
|
+
_validationErrors.current = [];
|
|
86
|
+
if (_input.current) {
|
|
87
|
+
if (multiple) {
|
|
88
|
+
// Seçilmiş olan dosyalar validasyona gönderiliyor.
|
|
89
|
+
selectedFiles.forEach((f) => handleValidationFile(f));
|
|
90
|
+
const inValidFiles = Array.from(new Set(_validationErrors.current));
|
|
84
91
|
// Input içerisine dosyalar aktarılıyor.
|
|
85
|
-
dataTransfer.items.add(
|
|
92
|
+
selectedFiles.forEach((f) => dataTransfer.items.add(f));
|
|
86
93
|
_input.current.files = dataTransfer.files;
|
|
94
|
+
// Geçerli olan dosyalar alındı...
|
|
95
|
+
const validFiles = [...selectedFiles.filter((x) => !inValidFiles.includes(x.name))];
|
|
96
|
+
validFiles.forEach((f) => fileFormData.append("file", f));
|
|
97
|
+
// Geçerli olan dosyalar base64'e dönüştürülüyor...
|
|
98
|
+
const base64Array = await Promise.all(validFiles.map((validFile) => handleFileToBase64(validFile)));
|
|
99
|
+
onChange(fileFormData, validFiles, base64Array, _validationErrors.current.length === 0);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
if (selectedFile) {
|
|
103
|
+
handleValidationFile(selectedFile);
|
|
104
|
+
fileFormData.append("file", selectedFile);
|
|
105
|
+
onChange(fileFormData, selectedFile, await handleFileToBase64(selectedFile));
|
|
106
|
+
setSelectedFileBase64(await handleFileToBase64(selectedFile));
|
|
107
|
+
// Input içerisine dosyalar aktarılıyor.
|
|
108
|
+
dataTransfer.items.add(selectedFile);
|
|
109
|
+
_input.current.files = dataTransfer.files;
|
|
110
|
+
}
|
|
87
111
|
}
|
|
88
112
|
}
|
|
89
|
-
}
|
|
113
|
+
})();
|
|
90
114
|
}, [selectedFiles, selectedFile]);
|
|
91
115
|
useEffect(() => {
|
|
92
116
|
if (_firstLoad.current)
|
|
@@ -97,25 +121,44 @@ const Upload = ({ text, file, onChange, allowedTypes, maxSize, multiple }) => {
|
|
|
97
121
|
return (React.createElement("div", { ref: _arUplaod, className: "ar-upload" },
|
|
98
122
|
React.createElement("input", { ref: _input, type: "file", onChange: (event) => handleFileChange(event.target.files), multiple: multiple }),
|
|
99
123
|
React.createElement("div", { className: "ar-upload-button" },
|
|
100
|
-
React.createElement(
|
|
124
|
+
React.createElement("div", { className: "button", onClick: () => {
|
|
101
125
|
if (_input.current)
|
|
102
126
|
_input.current.click();
|
|
103
|
-
} },
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
} },
|
|
128
|
+
uploadType === "image" && selectedFileBase64 && React.createElement("img", { src: selectedFileBase64 }),
|
|
129
|
+
(uploadType === "application-file" || !selectedFileBase64) && (React.createElement(React.Fragment, null,
|
|
130
|
+
React.createElement("div", { className: "information" },
|
|
131
|
+
React.createElement(ARIcon, { variant: "linear", icon: "Upload", stroke: "var(--gray-600)", fill: "transparent" }),
|
|
132
|
+
React.createElement("div", { className: "properies" },
|
|
133
|
+
allowedTypes && (React.createElement("div", { className: "allow-types" }, allowedTypes?.map((allowedType) => allowedType.split("/")[1].toLocaleUpperCase()).join(", "))),
|
|
134
|
+
maxSize && React.createElement("div", { className: "max-size" },
|
|
135
|
+
"up to ",
|
|
136
|
+
maxSize,
|
|
137
|
+
"MB"))),
|
|
138
|
+
text && React.createElement("span", null, text)))),
|
|
139
|
+
React.createElement("div", { className: "ar-upload-files" }, multiple ? (React.createElement("ul", null, selectedFiles.map((selectedFile, index) => {
|
|
140
|
+
let _className = [];
|
|
141
|
+
const errorMessages = validationErrors
|
|
142
|
+
.filter((error) => Object.keys(error).includes(selectedFile.name))
|
|
143
|
+
.map((error) => error[selectedFile.name]);
|
|
144
|
+
if (errorMessages.length > 0)
|
|
145
|
+
_className.push("error");
|
|
146
|
+
const content = (React.createElement("div", { className: "file" },
|
|
147
|
+
React.createElement("div", { className: "information" },
|
|
148
|
+
React.createElement("span", null, selectedFile.name),
|
|
149
|
+
React.createElement("span", null,
|
|
150
|
+
(selectedFile.size / 1024).toFixed(3),
|
|
151
|
+
"KB")),
|
|
152
|
+
React.createElement("div", { className: "delete", onClick: () => handleFileRemove(selectedFile) },
|
|
153
|
+
React.createElement(ARIcon, { icon: "CloseCircle", fill: "transparent", size: 20 }))));
|
|
154
|
+
return (React.createElement("li", { key: index, className: _className.map((c) => c).join(" ") }, errorMessages.length === 0 ? (content) : (React.createElement(Tooltip, { text: errorMessages.map((message) => message ?? "") }, content))));
|
|
155
|
+
}))) : (selectedFile && (React.createElement("div", { className: "file" },
|
|
156
|
+
React.createElement("div", { className: "information" },
|
|
157
|
+
React.createElement("span", null, selectedFile.name),
|
|
158
|
+
React.createElement("span", null,
|
|
159
|
+
(selectedFile.size / 1024).toFixed(3),
|
|
160
|
+
"KB")),
|
|
161
|
+
React.createElement("div", { className: "delete", onClick: () => handleFileRemove(selectedFile) },
|
|
162
|
+
React.createElement(ARIcon, { icon: "CloseCircle", fill: "transparent", size: 20 })))))))));
|
|
120
163
|
};
|
|
121
164
|
export default Upload;
|
|
@@ -48,6 +48,11 @@ class Icon {
|
|
|
48
48
|
return (React.createElement(React.Fragment, null,
|
|
49
49
|
React.createElement("path", { d: "M6 4v6a6 6 0 0 0 12 0V4", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
50
50
|
React.createElement("line", { x1: "4", y1: "20", x2: "20", y2: "20", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" })));
|
|
51
|
+
case "Upload":
|
|
52
|
+
return (React.createElement(React.Fragment, null,
|
|
53
|
+
React.createElement("path", { d: "M9 17v-6l-2 2M9 11l2 2", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
54
|
+
React.createElement("path", { d: "M22 10v5c0 5-2 7-7 7H9c-5 0-7-2-7-7V9c0-5 2-7 7-7h5", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
55
|
+
React.createElement("path", { d: "M22 10h-4c-3 0-4-1-4-4V2l8 8Z", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" })));
|
|
51
56
|
case "Strikethrough":
|
|
52
57
|
return (React.createElement(React.Fragment, null,
|
|
53
58
|
React.createElement("line", { x1: "4", y1: "12", x2: "20", y2: "12", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import Svg from "./Svg";
|
|
3
3
|
import Icon from "./Compiler";
|
|
4
|
-
export const ARIcon = ({ viewBox, size, variant = "linear", icon, fill = "var(--dark)", stroke = "var(--dark)", strokeWidth =
|
|
4
|
+
export const ARIcon = ({ viewBox, size, variant = "linear", icon, fill = "var(--dark)", stroke = "var(--dark)", strokeWidth = 1, style, }) => {
|
|
5
5
|
const { Compiler } = new Icon(fill, stroke, strokeWidth);
|
|
6
6
|
return (React.createElement(Svg, { viewBox: viewBox, fill: fill, width: size, height: size, style: style }, Compiler(variant, icon)));
|
|
7
7
|
};
|
|
@@ -20,7 +20,10 @@ declare class Api {
|
|
|
20
20
|
data?: any;
|
|
21
21
|
headers?: HeadersInit;
|
|
22
22
|
init?: Omit<RequestInit | undefined, "body">;
|
|
23
|
-
}): Promise<
|
|
23
|
+
}): Promise<{
|
|
24
|
+
p_response: Promise<Response>;
|
|
25
|
+
response: Response;
|
|
26
|
+
}>;
|
|
24
27
|
PostWithFormData(values: {
|
|
25
28
|
input?: RequestInfo;
|
|
26
29
|
data?: FormData;
|
|
@@ -29,13 +29,15 @@ class Api {
|
|
|
29
29
|
if (values.input && values.input.toString().includes("?")) {
|
|
30
30
|
values.input = values.input.toString().replace(/\/(?=\?)/, "");
|
|
31
31
|
}
|
|
32
|
-
const
|
|
32
|
+
const p_response = this.CustomFetch(`${this._url}${values.input}`, {
|
|
33
33
|
method: "POST",
|
|
34
34
|
headers: { ...this.HeaderProperties(), ...values.headers },
|
|
35
35
|
body: JSON.stringify(values.data),
|
|
36
36
|
...values.init,
|
|
37
37
|
});
|
|
38
|
-
|
|
38
|
+
const clone = (await p_response).clone();
|
|
39
|
+
const response = await clone;
|
|
40
|
+
return { p_response, response };
|
|
39
41
|
}
|
|
40
42
|
async PostWithFormData(values) {
|
|
41
43
|
if (values.input && values.input.toString().includes("?")) {
|
|
@@ -26,13 +26,13 @@ class Service {
|
|
|
26
26
|
let endPoint = `${this._endPoint}`;
|
|
27
27
|
if (values?.input)
|
|
28
28
|
endPoint += `/${values.input}`;
|
|
29
|
-
const response = await this._api.Post({
|
|
29
|
+
const { p_response, response } = await this._api.Post({
|
|
30
30
|
input: endPoint,
|
|
31
31
|
data: values?.data,
|
|
32
32
|
headers: values?.headers,
|
|
33
33
|
init: values?.init,
|
|
34
34
|
});
|
|
35
|
-
return await this.Response(
|
|
35
|
+
return await this.Response(p_response, response);
|
|
36
36
|
}
|
|
37
37
|
catch (error) {
|
|
38
38
|
throw new Error(error instanceof Error ? error.message : "Beklenmeyen bir hata oluştu.");
|