proje-react-panel 1.0.17-test5 → 1.0.17-test7
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/components/FormField.d.ts +5 -1
- package/dist/components/components/InnerForm.d.ts +8 -3
- package/dist/components/components/Uploader.d.ts +7 -0
- package/dist/components/components/index.d.ts +1 -1
- package/dist/components/components/list/ListPage.d.ts +1 -1
- package/dist/components/pages/FormPage.d.ts +8 -2
- package/dist/decorators/form/Input.d.ts +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/types/AnyClass.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/components/FormField.tsx +15 -6
- package/src/components/components/InnerForm.tsx +47 -8
- package/src/components/components/Uploader.tsx +66 -0
- package/src/components/components/index.ts +2 -2
- package/src/components/components/list/Datagrid.tsx +80 -73
- package/src/components/components/list/ListPage.tsx +11 -13
- package/src/components/pages/FormPage.tsx +8 -1
- package/src/decorators/form/Input.ts +3 -1
- package/src/decorators/form/getFormFields.ts +1 -0
- package/src/styles/form.scss +2 -4
- package/src/styles/index.scss +1 -0
- package/src/styles/list.scss +3 -1
- package/src/styles/uploader.scss +86 -0
- package/src/types/AnyClass.ts +3 -1
- package/src/components/components/ImageUploader.tsx +0 -301
@@ -1,301 +0,0 @@
|
|
1
|
-
import React, { useEffect } from "react";
|
2
|
-
import { useFormContext } from "react-hook-form";
|
3
|
-
import { bytesToSize } from "../../utils/format";
|
4
|
-
|
5
|
-
interface ThumbnailImageProps {
|
6
|
-
name: string;
|
7
|
-
src: string;
|
8
|
-
size: number;
|
9
|
-
style?: React.CSSProperties;
|
10
|
-
}
|
11
|
-
|
12
|
-
interface MultipleImageUploaderProps {
|
13
|
-
value?: Array<{ file: File; image: string; remove?: boolean }>;
|
14
|
-
onError?: (error: string | null) => void;
|
15
|
-
onClear?: () => void;
|
16
|
-
reset?: any;
|
17
|
-
onFilesChange?: (files: File[]) => void;
|
18
|
-
}
|
19
|
-
|
20
|
-
interface FileWithPreview {
|
21
|
-
file: File;
|
22
|
-
image: string;
|
23
|
-
}
|
24
|
-
|
25
|
-
const uploadState = Object.freeze({
|
26
|
-
BEFORE: "before",
|
27
|
-
HOVER: "hover",
|
28
|
-
AFTER: "after",
|
29
|
-
} as const);
|
30
|
-
|
31
|
-
type UploadStateType = (typeof uploadState)[keyof typeof uploadState];
|
32
|
-
|
33
|
-
function ThumbnailImage(props: ThumbnailImageProps) {
|
34
|
-
return (
|
35
|
-
<div>
|
36
|
-
<img {...props} style={{ width: 100 }} />
|
37
|
-
<p>
|
38
|
-
{props.name} <span style={{ whiteSpace: "none" }}>({bytesToSize(props.size)})</span>
|
39
|
-
</p>
|
40
|
-
</div>
|
41
|
-
);
|
42
|
-
}
|
43
|
-
|
44
|
-
export function ImageUploader() {
|
45
|
-
const {
|
46
|
-
register,
|
47
|
-
formState: { errors },
|
48
|
-
watch,
|
49
|
-
setValue,
|
50
|
-
clearErrors,
|
51
|
-
setError,
|
52
|
-
} = useFormContext();
|
53
|
-
const up = watch("uploader");
|
54
|
-
|
55
|
-
useEffect(() => {
|
56
|
-
register("uploader", { required: true });
|
57
|
-
}, [register]);
|
58
|
-
|
59
|
-
return (
|
60
|
-
<div>
|
61
|
-
<span className="form-error" style={{ bottom: 2, top: "unset" }}>
|
62
|
-
{errors.uploader?.type === "required" && "At least 1 image is required!"}
|
63
|
-
{errors.uploader?.type === "custom" && errors.uploader.message?.toString()}
|
64
|
-
</span>
|
65
|
-
<MultipleImageUploader
|
66
|
-
reset={up}
|
67
|
-
onError={(data: string | null) => {
|
68
|
-
if (!data) {
|
69
|
-
setValue("uploader", { files: [] });
|
70
|
-
clearErrors("uploader");
|
71
|
-
} else {
|
72
|
-
setError("uploader", {
|
73
|
-
type: "custom",
|
74
|
-
message: data,
|
75
|
-
});
|
76
|
-
}
|
77
|
-
}}
|
78
|
-
onClear={() => {
|
79
|
-
setValue("uploader", { files: [] });
|
80
|
-
clearErrors("uploader");
|
81
|
-
}}
|
82
|
-
onFilesChange={(files) => {
|
83
|
-
setValue("uploader", { files });
|
84
|
-
}}
|
85
|
-
/>
|
86
|
-
</div>
|
87
|
-
);
|
88
|
-
}
|
89
|
-
|
90
|
-
export function MultipleImageUploader(props: MultipleImageUploaderProps) {
|
91
|
-
const [currentUploadState, setUploadState] = React.useState<UploadStateType>(uploadState.BEFORE);
|
92
|
-
const [images, setImages] = React.useState<Array<{ file: File; image: string; remove?: boolean }>>(
|
93
|
-
props.value || []
|
94
|
-
);
|
95
|
-
const [files, setFiles] = React.useState<FileWithPreview[]>([]);
|
96
|
-
const [counter, setCounter] = React.useState(0);
|
97
|
-
console.log("files", files);
|
98
|
-
const dropzoneElement = React.useRef<HTMLDivElement>(null);
|
99
|
-
const imageInputRef = React.useRef<HTMLInputElement>(null);
|
100
|
-
|
101
|
-
React.useEffect(() => {
|
102
|
-
const element = dropzoneElement.current;
|
103
|
-
if (!element) return;
|
104
|
-
|
105
|
-
const handleDragEnter = (e: DragEvent) => {
|
106
|
-
e.preventDefault();
|
107
|
-
e.stopPropagation();
|
108
|
-
dragEnter();
|
109
|
-
};
|
110
|
-
|
111
|
-
const handleDragLeave = (e: DragEvent) => {
|
112
|
-
e.preventDefault();
|
113
|
-
e.stopPropagation();
|
114
|
-
dragLeave();
|
115
|
-
};
|
116
|
-
|
117
|
-
const handleDragOver = (e: DragEvent) => {
|
118
|
-
e.preventDefault();
|
119
|
-
e.stopPropagation();
|
120
|
-
};
|
121
|
-
|
122
|
-
const handleDrop = (e: DragEvent) => {
|
123
|
-
e.preventDefault();
|
124
|
-
e.stopPropagation();
|
125
|
-
setCounter(0);
|
126
|
-
const droppedFiles = e.dataTransfer?.files;
|
127
|
-
if (!droppedFiles) return;
|
128
|
-
|
129
|
-
setFiles([]);
|
130
|
-
setUploadState(uploadState.AFTER);
|
131
|
-
|
132
|
-
const newFiles: File[] = [];
|
133
|
-
for (let i = 0; i < droppedFiles.length; i++) {
|
134
|
-
const reader = new FileReader();
|
135
|
-
reader.onload = (event) => {
|
136
|
-
if (!event.target) return;
|
137
|
-
const check = onFileChange([
|
138
|
-
...files,
|
139
|
-
{ file: droppedFiles[i], image: event.target.result as string },
|
140
|
-
]);
|
141
|
-
if (check) {
|
142
|
-
newFiles.push(droppedFiles[i]);
|
143
|
-
if (imageInputRef.current) {
|
144
|
-
imageInputRef.current.files = droppedFiles;
|
145
|
-
}
|
146
|
-
setFiles([]);
|
147
|
-
}
|
148
|
-
// Notify parent of file changes
|
149
|
-
if (props.onFilesChange) {
|
150
|
-
props.onFilesChange(newFiles);
|
151
|
-
}
|
152
|
-
};
|
153
|
-
reader.readAsDataURL(droppedFiles[i]);
|
154
|
-
}
|
155
|
-
if (imageInputRef.current) {
|
156
|
-
imageInputRef.current.files = droppedFiles;
|
157
|
-
}
|
158
|
-
};
|
159
|
-
|
160
|
-
element.addEventListener("dragenter", handleDragEnter, false);
|
161
|
-
element.addEventListener("dragleave", handleDragLeave, false);
|
162
|
-
element.addEventListener("dragover", handleDragOver, false);
|
163
|
-
element.addEventListener("drop", handleDrop, false);
|
164
|
-
|
165
|
-
return () => {
|
166
|
-
element.removeEventListener("dragenter", handleDragEnter);
|
167
|
-
element.removeEventListener("dragleave", handleDragLeave);
|
168
|
-
element.removeEventListener("dragover", handleDragOver);
|
169
|
-
element.removeEventListener("drop", handleDrop);
|
170
|
-
};
|
171
|
-
}, [files]);
|
172
|
-
|
173
|
-
const dragEnter = () => {
|
174
|
-
setCounter((prev) => prev + 1);
|
175
|
-
setUploadState(uploadState.HOVER);
|
176
|
-
};
|
177
|
-
|
178
|
-
const dragLeave = () => {
|
179
|
-
setCounter((prev) => {
|
180
|
-
if (prev - 1 === 0) {
|
181
|
-
setUploadState(uploadState.BEFORE);
|
182
|
-
return 0;
|
183
|
-
}
|
184
|
-
return prev - 1;
|
185
|
-
});
|
186
|
-
};
|
187
|
-
|
188
|
-
const clickRemoveImage = (i: number) => {
|
189
|
-
const sources = [...images];
|
190
|
-
sources[i].remove = !sources[i].remove;
|
191
|
-
setImages(sources);
|
192
|
-
};
|
193
|
-
|
194
|
-
const clickRemoveFile = () => {
|
195
|
-
setFiles([]);
|
196
|
-
if (imageInputRef.current) {
|
197
|
-
imageInputRef.current.value = "";
|
198
|
-
}
|
199
|
-
props.onClear?.();
|
200
|
-
};
|
201
|
-
|
202
|
-
const checkValid = (filesInner: FileWithPreview[]): string | null => {
|
203
|
-
if (!filesInner) return null;
|
204
|
-
if (filesInner.length >= 10) return "you can't send more than 10 images";
|
205
|
-
for (let i = 0; i < filesInner.length; i++) {
|
206
|
-
const file = filesInner[i].file;
|
207
|
-
const split = file.name.split(".");
|
208
|
-
if (!["png", "jpg", "jpeg"].includes(split[split.length - 1])) {
|
209
|
-
return `Extension of the file can only be "png", "jpg" or "jpeg" `;
|
210
|
-
}
|
211
|
-
if (file) {
|
212
|
-
if (file.size > 1048576) {
|
213
|
-
return `Size of "${file.name}" can't be bigger than 1mb`;
|
214
|
-
}
|
215
|
-
}
|
216
|
-
}
|
217
|
-
return null;
|
218
|
-
};
|
219
|
-
|
220
|
-
const onFileChange = (filesInner: FileWithPreview[]): string | null => {
|
221
|
-
const check = checkValid(filesInner);
|
222
|
-
if (!check) {
|
223
|
-
setFiles(filesInner);
|
224
|
-
}
|
225
|
-
props.onError?.(check);
|
226
|
-
return check;
|
227
|
-
};
|
228
|
-
|
229
|
-
const renderImages = () => {
|
230
|
-
const imageElements = [];
|
231
|
-
if (files) {
|
232
|
-
console.log("---->", files);
|
233
|
-
for (let i = 0; i < files.length; i++) {
|
234
|
-
let imageClassName = "image";
|
235
|
-
imageElements.push(
|
236
|
-
<div key={i} className="image-container">
|
237
|
-
<div className={imageClassName}>
|
238
|
-
<ThumbnailImage name={files[i].file.name} src={files[i].image} size={files[i].file.size} />
|
239
|
-
</div>
|
240
|
-
</div>
|
241
|
-
);
|
242
|
-
}
|
243
|
-
}
|
244
|
-
return imageElements;
|
245
|
-
};
|
246
|
-
|
247
|
-
return (
|
248
|
-
<div ref={dropzoneElement} className={"multi-image form-element dropzone " + currentUploadState}>
|
249
|
-
<input ref={imageInputRef} type="file" style={{ display: "none" }} className="target" name={"file"} />
|
250
|
-
<div className="container">
|
251
|
-
<button className="trash" onClick={clickRemoveFile} type="button">
|
252
|
-
Delete All
|
253
|
-
</button>
|
254
|
-
{renderImages()}
|
255
|
-
<div>
|
256
|
-
<button
|
257
|
-
type={"button"}
|
258
|
-
onClick={() => {
|
259
|
-
const fileInput = document.getElementById("file__") as HTMLInputElement;
|
260
|
-
if (fileInput) {
|
261
|
-
fileInput.click();
|
262
|
-
}
|
263
|
-
}}
|
264
|
-
className="plus">
|
265
|
-
<span>
|
266
|
-
+ Add Image
|
267
|
-
<p>Drag image here or Select Image</p>
|
268
|
-
</span>
|
269
|
-
</button>
|
270
|
-
</div>
|
271
|
-
<input
|
272
|
-
hidden
|
273
|
-
id={"file__"}
|
274
|
-
multiple
|
275
|
-
type={"file"}
|
276
|
-
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
277
|
-
const selectedFiles = event.target.files;
|
278
|
-
if (!selectedFiles) return;
|
279
|
-
|
280
|
-
setFiles([]);
|
281
|
-
setUploadState(uploadState.AFTER);
|
282
|
-
for (let i = 0; i < selectedFiles.length; i++) {
|
283
|
-
const reader = new FileReader();
|
284
|
-
reader.onload = (eventInner) => {
|
285
|
-
if (!eventInner.target) return;
|
286
|
-
onFileChange([
|
287
|
-
...files,
|
288
|
-
{ file: selectedFiles[i], image: eventInner.target.result as string },
|
289
|
-
]);
|
290
|
-
};
|
291
|
-
reader.readAsDataURL(selectedFiles[i]);
|
292
|
-
}
|
293
|
-
if (imageInputRef.current) {
|
294
|
-
imageInputRef.current.files = selectedFiles;
|
295
|
-
}
|
296
|
-
}}
|
297
|
-
/>
|
298
|
-
</div>
|
299
|
-
</div>
|
300
|
-
);
|
301
|
-
}
|