@@ -5,22 +5,44 @@ const props = withDefaults(defineProps<{
5
5
multiple? : boolean
6
6
accept? : string
7
7
title? : string
8
+ pasteImage? : boolean
8
9
}>(), {
9
10
multiple: false ,
10
11
accept: undefined ,
11
12
title: ' Drag and drop files here, or click to select files' ,
13
+ pasteImage: false ,
12
14
});
13
15
14
16
const emit = defineEmits <{
15
17
(event : ' filesUpload' , files : File []): void
16
18
(event : ' fileUpload' , file : File ): void
17
19
}>();
18
20
19
- const { multiple } = toRefs (props );
21
+ const { multiple, pasteImage } = toRefs (props );
20
22
21
23
const isOverDropZone = ref (false );
22
24
25
+ function toBase64(file : File ) {
26
+ return new Promise <string >((resolve , reject ) => {
27
+ const reader = new FileReader ();
28
+ reader .readAsDataURL (file );
29
+ reader .onload = () => resolve (reader .result ?.toString () ?? ' ' );
30
+ reader .onerror = error => reject (error );
31
+ });
32
+ }
33
+
23
34
const fileInput = ref <HTMLInputElement | null >(null );
35
+ const imgPreview = ref <HTMLImageElement | null >(null );
36
+ async function handlePreview(image : File ) {
37
+ if (imgPreview .value ) {
38
+ imgPreview .value .src = await toBase64 (image );
39
+ }
40
+ }
41
+ function clearPreview() {
42
+ if (imgPreview .value ) {
43
+ imgPreview .value .src = ' ' ;
44
+ }
45
+ }
24
46
25
47
function triggerFileInput() {
26
48
fileInput .value ?.click ();
@@ -39,7 +61,30 @@ function handleDrop(event: DragEvent) {
39
61
handleUpload (files );
40
62
}
41
63
42
- function handleUpload(files : FileList | null | undefined ) {
64
+ async function onPasteImage(evt : ClipboardEvent ) {
65
+ if (! pasteImage .value ) {
66
+ return false ;
67
+ }
68
+
69
+ const items = evt .clipboardData ?.items ;
70
+ if (! items ) {
71
+ return false ;
72
+ }
73
+ for (let i = 0 ; i < items .length ; i ++ ) {
74
+ if (items [i ].type .includes (' image' )) {
75
+ const imageFile = items [i ].getAsFile ();
76
+ if (imageFile ) {
77
+ await handlePreview (imageFile );
78
+ emit (' fileUpload' , imageFile );
79
+ }
80
+ }
81
+ }
82
+ return true ;
83
+ }
84
+
85
+ async function handleUpload(files : FileList | null | undefined ) {
86
+ clearPreview ();
87
+
43
88
if (_ .isNil (files ) || _ .isEmpty (files )) {
44
89
return ;
45
90
}
@@ -49,6 +94,7 @@ function handleUpload(files: FileList | null | undefined) {
49
94
return ;
50
95
}
51
96
97
+ await handlePreview (files [0 ]);
52
98
emit (' fileUpload' , files [0 ]);
53
99
}
54
100
</script >
@@ -60,6 +106,7 @@ function handleUpload(files: FileList | null | undefined) {
60
106
'border-primary border-opacity-100': isOverDropZone,
61
107
}"
62
108
@click =" triggerFileInput"
109
+ @paste.prevent =" onPasteImage"
63
110
@drop.prevent =" handleDrop"
64
111
@dragover.prevent
65
112
@dragenter =" isOverDropZone = true"
@@ -73,6 +120,7 @@ function handleUpload(files: FileList | null | undefined) {
73
120
:accept =" accept"
74
121
@change =" handleFileInput"
75
122
>
123
+
76
124
<slot >
77
125
<span op-70 >
78
126
{{ title }}
@@ -90,6 +138,22 @@ function handleUpload(files: FileList | null | undefined) {
90
138
<c-button >
91
139
Browse files
92
140
</c-button >
141
+
142
+ <div v-if =" pasteImage" >
143
+ <!-- separator -->
144
+ <div my-4 w-full flex items-center justify-center op-70 >
145
+ <div class =" h-1px max-w-100px flex-1 bg-gray-300 op-50" />
146
+ <div class =" mx-2 text-gray-400" >
147
+ or
148
+ </div >
149
+ <div class =" h-1px max-w-100px flex-1 bg-gray-300 op-50" />
150
+ </div >
151
+
152
+ <p >Paste an image from clipboard</p >
153
+ </div >
93
154
</slot >
155
+ <div mt-2 >
156
+ <img ref =" imgPreview" width =" 150" >
157
+ </div >
94
158
</div >
95
159
</template >
0 commit comments