ar-design 0.2.78 → 0.2.80

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.
@@ -0,0 +1,136 @@
1
+ .ar-upload-button > .button.multiple > .preview {
2
+ display: flex;
3
+ flex-direction: row;
4
+ flex-wrap: nowrap;
5
+ width: 100%;
6
+ height: 100%;
7
+ border-right: solid 1px rgba(var(--black-rgb), 0.75);
8
+ }
9
+ .ar-upload-button > .button.multiple > .preview > .selected-image {
10
+ height: 100%;
11
+ object-fit: fill;
12
+ object-position: top;
13
+ }
14
+
15
+ .ar-upload-button > .button.multiple > .items {
16
+ display: flex;
17
+ flex-direction: column;
18
+ flex-wrap: nowrap;
19
+ background-color: var(--primary);
20
+ backdrop-filter: blur(5px);
21
+ width: 10rem;
22
+ height: 12.5rem;
23
+ overflow-x: hidden;
24
+ overflow-y: auto;
25
+ }
26
+ .ar-upload-button > .button.multiple > .items > .item {
27
+ --size: 5rem;
28
+
29
+ position: relative;
30
+ min-width: var(--size);
31
+ min-height: var(--size);
32
+ height: var(--size);
33
+ border-bottom: solid 1px rgba(var(--black-rgb), 0.75);
34
+ overflow: hidden;
35
+ }
36
+ .ar-upload-button > .button.multiple > .items > .item > .buttons {
37
+ position: absolute;
38
+ inset: 0;
39
+ display: flex;
40
+ justify-content: center;
41
+ align-items: center;
42
+ }
43
+ .ar-upload-button > .button.multiple > .items > .item > .buttons::before {
44
+ position: absolute;
45
+ inset: 0;
46
+ content: "";
47
+ background-color: transparent;
48
+ z-index: 1;
49
+ transition: background-color 250ms ease-in-out;
50
+ }
51
+ .ar-upload-button > .button.multiple > .items > .item > .buttons:hover::before {
52
+ background-color: rgba(var(--black-rgb), 0.75);
53
+ }
54
+ .ar-upload-button > .button.multiple > .items > .item > .buttons > div {
55
+ display: flex;
56
+ flex-direction: row;
57
+ visibility: hidden;
58
+ opacity: 0;
59
+ z-index: 2;
60
+ transition: visibility 250ms, opacity 250ms ease-in-out;
61
+ }
62
+ .ar-upload-button > .button.multiple > .items > .item > .buttons:hover div {
63
+ visibility: visible;
64
+ opacity: 1;
65
+ }
66
+ .ar-upload-button > .button.multiple > .items > .item > img {
67
+ width: 100%;
68
+ height: 100%;
69
+ object-fit: cover;
70
+ object-position: top;
71
+ }
72
+ .ar-upload-button > .button.multiple > .items > .item .error {
73
+ position: absolute;
74
+ inset: 0;
75
+ display: flex;
76
+ flex-direction: column;
77
+ justify-content: center;
78
+ align-items: center;
79
+ gap: 0.5rem;
80
+ background-color: rgba(var(--danger-rgb), 0.5);
81
+ color: var(--white);
82
+ font-size: 0.75rem;
83
+ font-weight: 700;
84
+ text-align: center;
85
+ z-index: 5;
86
+ }
87
+
88
+ .ar-upload-button > .button.multiple > .preview > .informations {
89
+ visibility: visible;
90
+ opacity: 1;
91
+ display: flex;
92
+ flex-direction: row;
93
+ flex-wrap: wrap;
94
+ justify-content: space-between;
95
+ align-items: center;
96
+ gap: 0.5rem;
97
+ position: absolute;
98
+ inset: auto 7.5rem 0 0;
99
+ background-color: rgba(var(--black-rgb), 0.75);
100
+ padding: 0.5rem;
101
+ transition: visibility 250ms, opacity 250ms ease-in-out;
102
+ }
103
+ .ar-upload-button > .button.multiple > .preview > .informations > .file-name {
104
+ color: var(--white);
105
+ font-size: 0.75rem;
106
+ font-weight: 700;
107
+ }
108
+ .ar-upload-button > .button.multiple > .preview > .informations > div {
109
+ display: flex;
110
+ gap: 0.25rem;
111
+ }
112
+ .ar-upload-button > .button.multiple > .preview > .informations > div > .file-size {
113
+ background-color: var(--primary);
114
+ padding: 0.25rem 0 0.25rem 0.25rem;
115
+ border-radius: var(--border-radius-sm);
116
+ color: var(--white);
117
+ font-size: 0.75rem;
118
+ font-weight: 700;
119
+ }
120
+ .ar-upload-button > .button.multiple > .preview > .informations > div > .file-size > .size-type {
121
+ background-color: rgba(var(--black-rgb), 0.5);
122
+ margin-left: 0.25rem;
123
+ border-top-right-radius: var(--border-radius-sm);
124
+ border-bottom-right-radius: var(--border-radius-sm);
125
+ padding: 0.25rem;
126
+ color: var(--primary);
127
+ font-weight: 700;
128
+ }
129
+ .ar-upload-button > .button.multiple > .preview > .informations > div > .file-type {
130
+ background-color: var(--warning);
131
+ padding: 0.25rem;
132
+ border-radius: var(--border-radius-sm);
133
+ color: var(--black);
134
+ font-size: 0.75rem;
135
+ font-weight: 700;
136
+ }
@@ -18,89 +18,150 @@
18
18
  }
19
19
 
20
20
  .ar-upload-button > .button {
21
+ position: relative;
21
22
  display: flex;
22
23
  flex-direction: column;
23
24
  justify-content: center;
24
25
  align-items: center;
25
26
  gap: 1rem;
26
- padding: 1rem 0;
27
+ height: 8.5rem;
27
28
  border: dashed 1px var(--gray-300);
28
29
  border-radius: var(--border-radius-sm);
29
30
  cursor: pointer;
30
31
  user-select: none;
32
+ transition: border 250ms, box-shadow 250ms ease-in-out;
33
+ }
34
+ .ar-upload-button > .button.multiple {
35
+ height: 12.5rem !important;
36
+ }
37
+ .ar-upload-button > .button.has-file {
38
+ flex-direction: row !important;
39
+ justify-content: flex-end !important;
40
+ gap: 0 !important;
41
+ align-items: flex-start !important;
42
+ }
43
+ .ar-upload-button > .button:not(.multiple):hover .preview > .informations {
44
+ visibility: hidden;
45
+ opacity: 0;
31
46
  }
32
- .ar-upload-button > .button:has(> img) {
47
+ .ar-upload-button > .button:not(.multiple):has(.preview > img):hover {
48
+ border: solid 1px transparent !important;
49
+ }
50
+ .ar-upload-button > .button:has(.preview > img) {
33
51
  padding: 0;
34
- border: none;
52
+ border: solid 1px rgba(var(--black-rgb), 0.75);
35
53
  overflow: hidden;
36
54
  }
37
- .ar-upload-button > .button > img {
38
- width: 100%;
39
- height: 200px;
40
- object-fit: fill;
41
- object-position: top;
55
+ .ar-upload-button > .button.dragging {
56
+ box-shadow: 0 0 0 2.5px rgba(var(--primary-rgb), 0.75);
42
57
  }
43
- .ar-upload-button > .button > .information {
58
+
59
+ .ar-upload-button > .button > .preview > .buttons {
60
+ position: absolute;
61
+ inset: 0;
44
62
  display: flex;
45
- flex-direction: column;
46
63
  justify-content: center;
47
64
  align-items: center;
48
- gap: 0.5rem;
49
65
  }
50
- .ar-upload-button > .button > .information > .properies {
66
+ .ar-upload-button > .button > .preview > .buttons::before {
67
+ position: absolute;
68
+ inset: 0;
69
+ content: "";
70
+ background-color: transparent;
71
+ z-index: 1;
72
+ transition: background-color 250ms ease-in-out;
73
+ }
74
+ .ar-upload-button > .button > .preview > .buttons:hover::before {
75
+ background-color: rgba(var(--black-rgb), 0.75);
76
+ }
77
+ .ar-upload-button > .button > .preview > .buttons > div {
51
78
  display: flex;
52
79
  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);
80
+ visibility: hidden;
81
+ opacity: 0;
82
+ z-index: 2;
83
+ transition: visibility 250ms, opacity 250ms ease-in-out;
58
84
  }
59
- .ar-upload-button > .button > .information > .properies > .allow-types {
60
- color: var(--gray-500);
85
+ .ar-upload-button > .button > .preview > .buttons:hover div {
86
+ visibility: visible;
87
+ opacity: 1;
61
88
  }
62
-
63
- .ar-upload-button > .ar-upload-files {
89
+ .ar-upload-button > .button > .preview > img {
64
90
  width: 100%;
65
- transition: top 250ms ease-in-out;
66
- }
67
- .ar-upload-button > .ar-upload-files > ul {
68
- list-style: none;
91
+ height: 100%;
92
+ object-fit: fill;
93
+ object-position: top;
69
94
  }
70
95
 
71
- .ar-upload-button > .ar-upload-files > ul > li > .file,
72
- .ar-upload-button > .ar-upload-files > .file {
96
+ .ar-upload-button > .button > .preview > .informations {
97
+ visibility: visible;
98
+ opacity: 1;
73
99
  display: flex;
74
100
  flex-direction: row;
101
+ flex-wrap: wrap;
75
102
  justify-content: space-between;
76
103
  align-items: center;
77
- background-color: var(--gray-200);
78
- margin-top: 0.5rem;
104
+ gap: 0.5rem;
105
+ position: absolute;
106
+ inset: auto 0 0 0;
107
+ background-color: rgba(var(--black-rgb), 0.75);
79
108
  padding: 0.5rem;
80
- border-radius: var(--border-radius-sm);
109
+ transition: visibility 250ms, opacity 250ms ease-in-out;
81
110
  }
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;
111
+ .ar-upload-button > .button > .preview > .informations > .file-name {
112
+ color: var(--white);
113
+ font-size: 0.75rem;
114
+ font-weight: 700;
87
115
  }
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;
116
+ .ar-upload-button > .button > .preview > .informations > div {
117
+ display: flex;
118
+ gap: 0.25rem;
91
119
  }
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 {
120
+ .ar-upload-button > .button > .preview > .informations > div > .file-size {
94
121
  background-color: var(--primary);
95
- padding: 0 0.25rem;
122
+ padding: 0.25rem 0 0.25rem 0.25rem;
96
123
  border-radius: var(--border-radius-sm);
97
124
  color: var(--white);
98
125
  font-size: 0.75rem;
99
- line-height: 2;
126
+ font-weight: 700;
127
+ }
128
+ .ar-upload-button > .button > .preview > .informations > div > .file-size > .size-type {
129
+ background-color: rgba(var(--black-rgb), 0.5);
130
+ margin-left: 0.25rem;
131
+ border-top-right-radius: var(--border-radius-sm);
132
+ border-bottom-right-radius: var(--border-radius-sm);
133
+ padding: 0.25rem;
134
+ color: var(--primary);
135
+ font-weight: 700;
136
+ }
137
+ .ar-upload-button > .button > .preview > .informations > div > .file-type {
138
+ background-color: var(--warning);
139
+ padding: 0.25rem;
140
+ border-radius: var(--border-radius-sm);
141
+ color: var(--black);
142
+ font-size: 0.75rem;
143
+ font-weight: 700;
100
144
  }
101
- .ar-upload-button > .ar-upload-files > ul > li > .file > .delete,
102
- .ar-upload-button > .ar-upload-files > .file > .delete {
103
- cursor: pointer;
145
+
146
+ .ar-upload-button > .button > .upload {
147
+ display: flex;
148
+ flex-direction: column;
149
+ justify-content: center;
150
+ align-items: center;
151
+ gap: 0.5rem;
152
+ }
153
+ .ar-upload-button > .button > .upload > .properies {
154
+ display: flex;
155
+ flex-direction: row;
156
+ gap: 0.5rem;
157
+ font-size: 0.85rem;
158
+ }
159
+ .ar-upload-button > .button > .upload > .properies > .max-size {
160
+ color: var(--gray-500);
161
+ }
162
+ .ar-upload-button > .button > .upload > .properies > .allow-types {
163
+ color: var(--gray-500);
104
164
  }
105
165
 
166
+ @import url("./preview-selected-files.css");
106
167
  @import url("./animations.css");
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ interface IProps {
3
+ selectedFile: File | undefined;
4
+ handleFileToBase64: (file: File) => Promise<string>;
5
+ handleFileRemove: (fileToRemove: File) => void;
6
+ }
7
+ declare const _default: React.MemoExoticComponent<({ selectedFile, handleFileToBase64, handleFileRemove }: IProps) => React.JSX.Element | undefined>;
8
+ export default _default;
@@ -0,0 +1,36 @@
1
+ import React, { memo, useEffect, useState } from "react";
2
+ import Button from "../button";
3
+ import { ARIcon } from "../../icons";
4
+ const PreviewSelectedFile = ({ selectedFile, handleFileToBase64, handleFileRemove }) => {
5
+ // states
6
+ const [selectedFileBase64, setSelectedFileBase64] = useState(undefined);
7
+ // useEffects
8
+ useEffect(() => {
9
+ (async () => {
10
+ if (!selectedFile)
11
+ return;
12
+ setSelectedFileBase64(await handleFileToBase64(selectedFile));
13
+ })();
14
+ }, [selectedFile]);
15
+ return (selectedFile && (React.createElement("div", { className: "preview" },
16
+ React.createElement("div", { className: "buttons" },
17
+ React.createElement("div", null,
18
+ React.createElement(Button, { variant: "borderless", icon: { element: React.createElement(ARIcon, { variant: "fill", icon: "Eye", fill: "currentColor" }) }, onClick: (event) => {
19
+ event.stopPropagation();
20
+ const newTab = window.open();
21
+ newTab?.document.write(`<img src="${selectedFileBase64}" title="${selectedFile.name}" alt="${selectedFile.name}" />`);
22
+ } }),
23
+ React.createElement(Button, { variant: "borderless", status: "danger", icon: { element: React.createElement(ARIcon, { variant: "fill", icon: "Trash", fill: "currentColor" }) }, onClick: (event) => {
24
+ event.stopPropagation();
25
+ handleFileRemove(selectedFile);
26
+ } }))),
27
+ React.createElement("img", { src: selectedFileBase64 }),
28
+ React.createElement("div", { className: "informations" },
29
+ React.createElement("span", { className: "file-name" }, selectedFile.name),
30
+ React.createElement("div", null,
31
+ React.createElement("span", { className: "file-size" },
32
+ (selectedFile.size / 1024).toFixed(3),
33
+ React.createElement("span", { className: "size-type" }, "KB")),
34
+ React.createElement("span", { className: "file-type" }, selectedFile.type.split("/")[1].toLocaleUpperCase()))))));
35
+ };
36
+ export default memo(PreviewSelectedFile);
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { ValidationError } from ".";
3
+ interface IProps {
4
+ selectedFiles: File[];
5
+ validationErrors: ValidationError[];
6
+ handleFileToBase64: (file: File) => Promise<string>;
7
+ handleFileRemove: (fileToRemove: File) => void;
8
+ }
9
+ declare const _default: React.MemoExoticComponent<({ selectedFiles, validationErrors, handleFileToBase64, handleFileRemove }: IProps) => false | React.JSX.Element>;
10
+ export default _default;
@@ -0,0 +1,53 @@
1
+ import React, { memo, useEffect, useState } from "react";
2
+ import Button from "../button";
3
+ import { ARIcon } from "../../icons";
4
+ const PreviewSelectedFiles = ({ selectedFiles, validationErrors, handleFileToBase64, handleFileRemove }) => {
5
+ // states
6
+ const [items, setItems] = useState([]);
7
+ const [selectedFile, setSelectedFile] = useState(undefined);
8
+ const [selectedFileBase64, setSelectedFileBase64] = useState(undefined);
9
+ // useEffects
10
+ useEffect(() => {
11
+ (async () => {
12
+ const items = await Promise.all(selectedFiles.map(async (selectedFile) => {
13
+ const _selectedFileBase64 = await handleFileToBase64(selectedFile);
14
+ const message = validationErrors.find((validationError) => validationError.fileName === selectedFile.name)?.message;
15
+ return (React.createElement("div", { className: "item", onClick: (event) => event.stopPropagation(), onMouseOver: async (event) => {
16
+ event.stopPropagation();
17
+ setSelectedFileBase64(await handleFileToBase64(selectedFile));
18
+ setSelectedFile(selectedFile);
19
+ } },
20
+ message && (React.createElement("div", { className: "error" },
21
+ React.createElement(ARIcon, { variant: "fill", icon: "ExclamationDiamond", fill: "var(--white)" }),
22
+ React.createElement("span", null, message))),
23
+ React.createElement("div", { className: "buttons" },
24
+ React.createElement("div", null,
25
+ React.createElement(Button, { variant: "borderless", icon: { element: React.createElement(ARIcon, { variant: "fill", icon: "Eye", fill: "currentColor" }) }, onClick: (event) => {
26
+ event.stopPropagation();
27
+ const newTab = window.open();
28
+ newTab?.document.write(`<img src="${_selectedFileBase64}" title="${selectedFile.name}" alt="${selectedFile.name}" />`);
29
+ } }),
30
+ React.createElement(Button, { variant: "borderless", status: "danger", icon: { element: React.createElement(ARIcon, { variant: "fill", icon: "Trash", fill: "currentColor" }) }, onClick: (event) => {
31
+ event.stopPropagation();
32
+ handleFileRemove(selectedFile);
33
+ } }))),
34
+ React.createElement("img", { src: _selectedFileBase64 })));
35
+ }));
36
+ setItems(items);
37
+ setSelectedFileBase64(await handleFileToBase64(selectedFiles[0]));
38
+ setSelectedFile(selectedFiles[0]);
39
+ })();
40
+ }, [selectedFiles, validationErrors]);
41
+ return (selectedFiles.length > 0 && (React.createElement(React.Fragment, null,
42
+ React.createElement("div", { className: "preview" },
43
+ React.createElement("img", { src: selectedFileBase64, className: "selected-image" }),
44
+ selectedFile && (React.createElement("div", { className: "informations" },
45
+ React.createElement("span", { className: "file-name" }, selectedFile.name),
46
+ React.createElement("div", null,
47
+ React.createElement("span", { className: "file-size" },
48
+ (selectedFile.size / 1024).toFixed(3),
49
+ React.createElement("span", { className: "size-type" }, "KB")),
50
+ React.createElement("span", { className: "file-type" }, selectedFile.type.split("/")[1].toLocaleUpperCase()))))),
51
+ React.createElement("div", { className: "items" }, items))));
52
+ };
53
+ export default memo(PreviewSelectedFiles);
@@ -1,5 +1,9 @@
1
1
  import React from "react";
2
2
  import Props from "./Props";
3
3
  import "../../../assets/css/components/form/upload/styles.css";
4
+ export type ValidationError = {
5
+ fileName: string;
6
+ message: string;
7
+ };
4
8
  declare const Upload: React.FC<Props>;
5
9
  export default Upload;
@@ -1,7 +1,8 @@
1
- import React, { useEffect, useRef, useState } from "react";
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
2
  import "../../../assets/css/components/form/upload/styles.css";
3
- import Tooltip from "../../feedback/tooltip";
4
3
  import { ARIcon } from "../../icons";
4
+ import PreviewSelectedFile from "./PreviewSelectedFile";
5
+ import PreviewSelectedFiles from "./PreviewSelectedFiles";
5
6
  const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-file", maxSize, multiple, }) => {
6
7
  // refs
7
8
  const _firstLoad = useRef(false);
@@ -9,13 +10,14 @@ const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-
9
10
  const _arUplaod = useRef(null);
10
11
  // refs -> File Data
11
12
  const _validationErrors = useRef([]);
13
+ // variables
14
+ const [className, setClassName] = useState(["button"]);
12
15
  // states
13
16
  const [selectedFile, setSelectedFile] = useState(undefined);
14
- const [selectedFileBase64, setSelectedFileBase64] = useState(undefined);
15
17
  const [selectedFiles, setSelectedFiles] = useState([]);
16
18
  const [validationErrors, setValidationErrors] = useState([]);
17
19
  // methods
18
- const handleFileChange = (files) => {
20
+ const handleFileChange = useCallback((files) => {
19
21
  const _files = Array.from(files ?? []);
20
22
  if (_files.length > 0) {
21
23
  if (multiple) {
@@ -32,8 +34,8 @@ const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-
32
34
  else {
33
35
  multiple ? setSelectedFiles(file) : setSelectedFile(file);
34
36
  }
35
- };
36
- const handleFileRemove = (fileToRemove) => {
37
+ }, []);
38
+ const handleFileRemove = useCallback((fileToRemove) => {
37
39
  if (multiple) {
38
40
  const dataTransfer = new DataTransfer();
39
41
  setSelectedFiles((prev) => {
@@ -41,32 +43,34 @@ const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-
41
43
  newList.forEach((file) => dataTransfer.items.add(file));
42
44
  if (_input.current)
43
45
  _input.current.files = dataTransfer.files;
46
+ if (newList.length === 0)
47
+ setClassName((prev) => prev.filter((c) => c !== "has-file"));
44
48
  return newList;
45
49
  });
46
50
  }
47
51
  else {
48
52
  setSelectedFile(undefined);
49
- setSelectedFileBase64(undefined);
53
+ setClassName((prev) => prev.filter((c) => c !== "has-file"));
50
54
  }
51
- };
52
- const handleValidationFile = (file) => {
55
+ }, []);
56
+ const handleValidationFile = useCallback((file) => {
53
57
  const newErrors = [];
54
58
  if (allowedTypes) {
55
59
  if (!allowedTypes.includes(file.type)) {
56
- newErrors.push({ [file.name]: "Geçersiz dosya türü." });
60
+ newErrors.push({ fileName: file.name, message: "Geçersiz dosya türü." });
57
61
  _validationErrors.current.push(file.name);
58
62
  }
59
63
  }
60
64
  if (maxSize) {
61
65
  const _maxSize = maxSize * 1024 * 1024; // MB
62
66
  if (file.size > _maxSize) {
63
- newErrors.push({ [file.name]: "Dosya boyutu çok büyük." });
67
+ newErrors.push({ fileName: file.name, message: "Dosya boyutu çok büyük." });
64
68
  _validationErrors.current.push(file.name);
65
69
  }
66
70
  }
67
71
  setValidationErrors((prev) => [...prev, ...newErrors]);
68
- };
69
- function handleFileToBase64(file) {
72
+ }, []);
73
+ const handleFileToBase64 = useCallback((file) => {
70
74
  return new Promise((resolve, reject) => {
71
75
  const reader = new FileReader();
72
76
  reader.onload = () => {
@@ -80,7 +84,37 @@ const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-
80
84
  reader.onerror = reject;
81
85
  reader.readAsDataURL(file);
82
86
  });
83
- }
87
+ }, []);
88
+ const handleDrag = useCallback((e) => {
89
+ e.preventDefault();
90
+ e.stopPropagation();
91
+ if (e.type === "dragenter" || e.type === "dragover") {
92
+ setClassName((prev) => {
93
+ const index = prev.findIndex((c) => c === "dragging");
94
+ if (index === -1)
95
+ return [...prev, "dragging"];
96
+ return prev;
97
+ });
98
+ }
99
+ else {
100
+ setClassName((prev) => prev.filter((c) => c !== "dragging"));
101
+ }
102
+ }, []);
103
+ const handleDrop = useCallback((e) => {
104
+ e.preventDefault();
105
+ e.stopPropagation();
106
+ const files = e.dataTransfer.files;
107
+ if (files && files.length > 0) {
108
+ if (multiple) {
109
+ setSelectedFiles(Array.from(files));
110
+ }
111
+ else {
112
+ setSelectedFile(files[files.length - 1]);
113
+ _firstLoad.current = true;
114
+ }
115
+ }
116
+ setClassName((prev) => prev.filter((c) => c !== "dragging"));
117
+ }, []);
84
118
  // useEffects
85
119
  useEffect(() => {
86
120
  (async () => {
@@ -90,6 +124,8 @@ const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-
90
124
  _validationErrors.current = [];
91
125
  if (_input.current) {
92
126
  if (multiple) {
127
+ if (selectedFiles.length === 0)
128
+ return;
93
129
  // Seçilmiş olan dosyalar validasyona gönderiliyor.
94
130
  selectedFiles.forEach((f) => handleValidationFile(f));
95
131
  const inValidFiles = Array.from(new Set(_validationErrors.current));
@@ -102,13 +138,19 @@ const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-
102
138
  // Geçerli olan dosyalar base64'e dönüştürülüyor...
103
139
  const base64Array = await Promise.all(validFiles.map((validFile) => handleFileToBase64(validFile)));
104
140
  onChange(fileFormData, validFiles, base64Array, _validationErrors.current.length === 0);
141
+ // Eğer dosya varsa.
142
+ setClassName((prev) => {
143
+ const index = prev.findIndex((c) => c === "has-file");
144
+ if (index === -1)
145
+ return [...prev, "has-file"];
146
+ return prev;
147
+ });
105
148
  }
106
149
  else {
107
150
  if (selectedFile) {
108
151
  handleValidationFile(selectedFile);
109
152
  fileFormData.append("file", selectedFile);
110
153
  onChange(fileFormData, selectedFile, await handleFileToBase64(selectedFile));
111
- setSelectedFileBase64(await handleFileToBase64(selectedFile));
112
154
  // Input içerisine dosyalar aktarılıyor.
113
155
  dataTransfer.items.add(selectedFile);
114
156
  _input.current.files = dataTransfer.files;
@@ -133,47 +175,28 @@ const Upload = ({ text, file, onChange, allowedTypes, uploadType = "application-
133
175
  _firstLoad.current = true;
134
176
  }
135
177
  }, [file]);
178
+ useEffect(() => {
179
+ if (multiple)
180
+ setClassName((prev) => [...prev, "multiple"]);
181
+ }, []);
136
182
  return (React.createElement("div", { ref: _arUplaod, className: "ar-upload" },
137
183
  React.createElement("input", { ref: _input, type: "file", onChange: (event) => handleFileChange(event.target.files), multiple: multiple }),
138
184
  React.createElement("div", { className: "ar-upload-button" },
139
- React.createElement("div", { className: "button", onClick: () => {
185
+ React.createElement("div", { className: className.map((c) => c).join(" "), onDragEnter: handleDrag, onDragLeave: handleDrag, onDragOver: handleDrag, onDrop: handleDrop, onClick: () => {
140
186
  if (_input.current)
141
187
  _input.current.click();
142
188
  } },
143
- uploadType === "image" && selectedFileBase64 && React.createElement("img", { src: selectedFileBase64 }),
144
- (uploadType === "application-file" || !selectedFileBase64) && (React.createElement(React.Fragment, null,
145
- React.createElement("div", { className: "information" },
146
- React.createElement(ARIcon, { variant: "linear", icon: "Upload", stroke: "var(--gray-600)", fill: "transparent" }),
189
+ uploadType === "image" &&
190
+ (multiple ? (React.createElement(PreviewSelectedFiles, { selectedFiles: selectedFiles, validationErrors: validationErrors, handleFileToBase64: handleFileToBase64, handleFileRemove: handleFileRemove })) : (React.createElement(PreviewSelectedFile, { selectedFile: selectedFile, handleFileToBase64: handleFileToBase64, handleFileRemove: handleFileRemove }))),
191
+ !selectedFile && selectedFiles.length === 0 && (React.createElement(React.Fragment, null,
192
+ React.createElement("div", { className: "upload" },
193
+ React.createElement(ARIcon, { variant: "fill", icon: "CloudUpload", size: 32 }),
147
194
  React.createElement("div", { className: "properies" },
148
195
  allowedTypes && (React.createElement("div", { className: "allow-types" }, allowedTypes?.map((allowedType) => allowedType.split("/")[1].toLocaleUpperCase()).join(", "))),
149
196
  maxSize && React.createElement("div", { className: "max-size" },
150
197
  "up to ",
151
198
  maxSize,
152
199
  "MB"))),
153
- text && React.createElement("span", null, text)))),
154
- React.createElement("div", { className: "ar-upload-files" }, multiple ? (React.createElement("ul", null, selectedFiles.map((selectedFile, index) => {
155
- let _className = [];
156
- const errorMessages = validationErrors
157
- .filter((error) => Object.keys(error).includes(selectedFile.name))
158
- .map((error) => error[selectedFile.name]);
159
- if (errorMessages.length > 0)
160
- _className.push("error");
161
- const content = (React.createElement("div", { className: "file" },
162
- React.createElement("div", { className: "information" },
163
- React.createElement("span", null, selectedFile.name),
164
- React.createElement("span", null,
165
- (selectedFile.size / 1024).toFixed(3),
166
- "KB")),
167
- React.createElement("div", { className: "delete", onClick: () => handleFileRemove(selectedFile) },
168
- React.createElement(ARIcon, { icon: "CloseCircle", fill: "transparent", size: 20 }))));
169
- 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))));
170
- }))) : (selectedFile && (React.createElement("div", { className: "file" },
171
- React.createElement("div", { className: "information" },
172
- React.createElement("span", null, selectedFile.name),
173
- React.createElement("span", null,
174
- (selectedFile.size / 1024).toFixed(3),
175
- "KB")),
176
- React.createElement("div", { className: "delete", onClick: () => handleFileRemove(selectedFile) },
177
- React.createElement(ARIcon, { icon: "CloseCircle", fill: "transparent", size: 20 })))))))));
200
+ text && React.createElement("span", null, text)))))));
178
201
  };
179
202
  export default Upload;
@@ -105,33 +105,25 @@ class Icon {
105
105
  return (React.createElement(React.Fragment, null,
106
106
  React.createElement("path", { d: "M12 7.75V13M2.92 8.58c0-1.12.6-2.16 1.57-2.73l5.94-3.43c.97-.56 2.17-.56 3.15 0l5.94 3.43c.97.56 1.57 1.6 1.57 2.73v6.84c0 1.12-.6 2.16-1.57 2.73l-5.94 3.43c-.97.56-2.17.56-3.15 0l-5.94-3.43a3.15 3.15 0 0 1-1.57-2.73v-2.76", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }),
107
107
  React.createElement("path", { d: "M12 16.2v.1", stroke: this._stroke, strokeWidth: this._strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" })));
108
+ case "ExclamationCircle":
109
+ return (React.createElement(React.Fragment, null,
110
+ React.createElement("path", { d: "M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16" }),
111
+ React.createElement("path", { d: "M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0M7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0z" })));
108
112
  default:
109
113
  return null;
110
114
  }
111
- case "bulk":
115
+ case "fill":
112
116
  switch (icon) {
113
- case "Drive":
114
- return (React.createElement(React.Fragment, null,
115
- React.createElement("path", { opacity: ".4", d: "M16.19 2H7.82C4.18 2 2.01 4.17 2.01 7.81v8.37c0 3.64 2.17 5.81 5.81 5.81h8.37c3.64 0 5.81-2.17 5.81-5.81V7.81C22 4.17 19.83 2 16.19 2Z", fill: this._fill }),
116
- React.createElement("path", { d: "M6 9c-.41 0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0 .41-.34.75-.75.75ZM10 9c-.41 0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0 .41-.34.75-.75.75ZM6 18.75c-.41 0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0 .41-.34.75-.75.75ZM10 18.75c-.41 0-.75-.34-.75-.75v-2c0-.41.34-.75.75-.75s.75.34.75.75v2c0 .41-.34.75-.75.75ZM18 8h-4c-.41 0-.75-.34-.75-.75s.34-.75.75-.75h4c.41 0 .75.34.75.75S18.41 8 18 8ZM18 17.75h-4c-.41 0-.75-.34-.75-.75s.34-.75.75-.75h4c.41 0 .75.34.75.75s-.34.75-.75.75ZM22 11.25H2v1.5h20v-1.5Z", fill: this._fill })));
117
- case "Folder":
118
- return (React.createElement(React.Fragment, null,
119
- React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "32", height: "32", viewBox: "0 0 24 24", fill: "none" },
120
- React.createElement("path", { d: "M22 11.071v5.58c0 2.95-2.4 5.35-5.35 5.35h-9.3c-2.95 0-5.35-2.4-5.35-5.35v-7.21h19.74c.15.45.23.91.25 1.4.01.07.01.16.01.23Z", fill: this._fill }),
121
- React.createElement("path", { opacity: ".4", d: "M21.74 9.44H2V6.42C2 3.98 3.98 2 6.42 2h2.33c1.63 0 2.14.53 2.79 1.4l1.4 1.86c.31.41.35.47.93.47h2.79c2.37-.01 4.39 1.55 5.08 3.71Z", fill: this._fill }))));
122
- case "Upload":
123
- return (React.createElement(React.Fragment, null,
124
- React.createElement("path", { d: "M20.5 10.19h-2.89c-2.37 0-4.3-1.93-4.3-4.3V3c0-.55-.45-1-1-1H8.07C4.99 2 2.5 4 2.5 7.57v8.86C2.5 20 4.99 22 8.07 22h7.86c3.08 0 5.57-2 5.57-5.57v-5.24c0-.55-.45-1-1-1Z", opacity: ".4", fill: this._fill }),
125
- React.createElement("path", { d: "M15.8 2.21c-.41-.41-1.12-.13-1.12.44v3.49c0 1.46 1.24 2.67 2.75 2.67.95.01 2.27.01 3.4.01.57 0 .87-.67.47-1.07-1.44-1.45-4.02-4.06-5.5-5.54ZM11.53 12.47l-2-2c-.01-.01-.02-.01-.02-.02a.855.855 0 0 0-.22-.15h-.02c-.08-.03-.16-.04-.24-.05h-.08c-.06 0-.13.02-.19.04-.03.01-.05.02-.07.03-.08.04-.16.08-.22.15l-2 2c-.29.29-.29.77 0 1.06.29.29.77.29 1.06 0l.72-.72V17c0 .41.34.75.75.75s.75-.34.75-.75v-4.19l.72.72c.15.15.34.22.53.22s.38-.07.53-.22c.29-.29.29-.77 0-1.06Z", fill: this._fill })));
126
- case "Image":
127
- return (React.createElement(React.Fragment, null,
128
- React.createElement("path", { opacity: ".4", d: "m22.019 16.82-3.13-7.32c-.57-1.34-1.42-2.1-2.39-2.15-.96-.05-1.89.62-2.6 1.9l-1.9 3.41c-.4.72-.97 1.15-1.59 1.2-.63.06-1.26-.27-1.77-.92l-.22-.28c-.71-.89-1.59-1.32-2.49-1.23-.9.09-1.67.71-2.18 1.72l-1.73 3.45c-.62 1.25-.56 2.7.17 3.88.73 1.18 2 1.89 3.39 1.89h12.76c1.34 0 2.59-.67 3.33-1.79.76-1.12.88-2.53.35-3.76Z", fill: this._fill }),
129
- React.createElement("path", { d: "M6.97 8.381a3.38 3.38 0 1 0 0-6.76 3.38 3.38 0 0 0 0 6.76Z", fill: this._fill })));
117
+ case "CloudUpload":
118
+ return (React.createElement("path", { fillRule: "evenodd", d: "M8 0a5.53 5.53 0 0 0-3.594 1.342c-.766.66-1.321 1.52-1.464 2.383C1.266 4.095 0 5.555 0 7.318 0 9.366 1.708 11 3.781 11H7.5V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11h4.188C14.502 11 16 9.57 16 7.773c0-1.636-1.242-2.969-2.834-3.194C12.923 1.999 10.69 0 8 0m-.5 14.5V11h1v3.5a.5.5 0 0 1-1 0" }));
130
119
  case "Trash":
120
+ return (React.createElement("path", { d: "M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5M8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5m3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0" }));
121
+ case "Eye":
131
122
  return (React.createElement(React.Fragment, null,
132
- React.createElement("path", { d: "M21.07 5.23c-1.61-.16-3.22-.28-4.84-.37v-.01l-.22-1.3c-.15-.92-.37-2.3-2.71-2.3h-2.62c-2.33 0-2.55 1.32-2.71 2.29l-.21 1.28c-.93.06-1.86.12-2.79.21l-2.04.2c-.42.04-.72.41-.68.82.04.41.4.71.82.67l2.04-.2c5.24-.52 10.52-.32 15.82.21h.08c.38 0 .71-.29.75-.68a.766.766 0 0 0-.69-.82Z", fill: this._fill }),
133
- React.createElement("path", { opacity: ".399", d: "M19.23 8.14c-.24-.25-.57-.39-.91-.39H5.68c-.34 0-.68.14-.91.39-.23.25-.36.59-.34.94l.62 10.26c.11 1.52.25 3.42 3.74 3.42h6.42c3.49 0 3.63-1.89 3.74-3.42l.62-10.25c.02-.36-.11-.7-.34-.95Z", fill: this._fill }),
134
- React.createElement("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M9.58 17a.75.75 0 0 1 .75-.75h3.33a.75.75 0 0 1 0 1.5h-3.33a.75.75 0 0 1-.75-.75ZM8.75 13a.75.75 0 0 1 .75-.75h5a.75.75 0 0 1 0 1.5h-5a.75.75 0 0 1-.75-.75Z", fill: this._fill })));
123
+ React.createElement("path", { d: "M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0" }),
124
+ React.createElement("path", { d: "M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8m8 3.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7" })));
125
+ case "ExclamationDiamond":
126
+ return (React.createElement("path", { d: "M9.05.435c-.58-.58-1.52-.58-2.1 0L.436 6.95c-.58.58-.58 1.519 0 2.098l6.516 6.516c.58.58 1.519.58 2.098 0l6.516-6.516c.58-.58.58-1.519 0-2.098zM8 4c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995A.905.905 0 0 1 8 4m.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2" }));
135
127
  default:
136
128
  return null;
137
129
  }
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
- import Svg from "./Svg";
3
2
  import Icon from "./Compiler";
4
- export const ARIcon = ({ viewBox, size, variant = "linear", icon, fill = "var(--dark)", stroke = "var(--dark)", strokeWidth = 1, style, }) => {
3
+ export const ARIcon = ({ viewBox, size = 16, variant = "linear", icon, fill = "var(--dark)", stroke = "var(--dark)", strokeWidth = 1, style, }) => {
5
4
  const { Compiler } = new Icon(fill, stroke, strokeWidth);
6
- return (React.createElement(Svg, { viewBox: viewBox, fill: fill, width: size, height: size, style: style }, Compiler(variant, icon)));
5
+ return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: viewBox ?? `0 0 16 16`, fill: fill, width: size, height: size, style: style }, Compiler(variant, icon)));
7
6
  };
@@ -68,8 +68,8 @@ export type Errors<TData> = Partial<{
68
68
  [key in keyof TData]: string;
69
69
  }>;
70
70
  export type AllowedTypes = "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/svg+xml" | "image/bmp" | "image/tiff" | "application/pdf" | "application/msword" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/zip" | "application/x-rar-compressed" | "application/x-7z-compressed" | "application/gzip" | "application/json" | "application/xml" | "text/plain" | "text/csv" | "text/html" | "video/mp4" | "video/quicktime" | "video/x-msvideo" | "video/x-matroska" | "video/webm" | "video/x-flv" | "audio/mpeg" | "audio/wav" | "audio/ogg" | "audio/aac" | "audio/flac" | "application/octet-stream";
71
- export type IconVariants = "linear" | "bulk";
72
- export type Icons = "Add" | "ArrowLeft" | "ArrowRight" | "CloseCircle" | "CloseSquare" | "Drive" | "Document" | "Folder" | "Trash" | "Upload" | "Image" | "Import" | "Bold" | "Italic" | "Underline" | "Success" | "Strikethrough" | "BulletList" | "NumberList" | "TextAlingLeft" | "TextAlingCenter" | "TextAlingRight" | "Filter" | "TickCircle" | "File" | "Warning";
71
+ export type IconVariants = "linear" | "fill";
72
+ export type Icons = "Add" | "ArrowLeft" | "ArrowRight" | "Bold" | "BulletList" | "CloseCircle" | "CloseSquare" | "CloudUpload" | "Document" | "Drive" | "ExclamationCircle" | "ExclamationDiamond" | "Eye" | "File" | "Filter" | "Folder" | "Image" | "Import" | "Italic" | "NumberList" | "Strikethrough" | "Success" | "TextAlingCenter" | "TextAlingLeft" | "TextAlingRight" | "TickCircle" | "Trash" | "Underline" | "Upload" | "Warning";
73
73
  export type PieChartDataType = {
74
74
  value: number;
75
75
  text: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ar-design",
3
- "version": "0.2.78",
3
+ "version": "0.2.80",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,4 +0,0 @@
1
- import React from "react";
2
- import { IChildren } from "../../libs/types/IGlobalProps";
3
- declare const Svg: React.FC<React.SVGProps<SVGElement> & IChildren>;
4
- export default Svg;
@@ -1,5 +0,0 @@
1
- import React from "react";
2
- const Svg = ({ children, viewBox, fill = "none", width = 32, height = 32, style, }) => {
3
- return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: viewBox ?? "0 0 24 24", fill: fill, width: width, height: height, style: style }, children));
4
- };
5
- export default Svg;