@leaflink/stash 44.3.1 → 44.5.0
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/FileUpload.js +183 -263
- package/dist/FileUpload.js.map +1 -1
- package/dist/FileUpload.vue.d.ts +98 -175
- package/dist/components.css +1 -1
- package/dist/locale.js +10 -8
- package/dist/locale.js.map +1 -1
- package/package.json +1 -1
package/dist/FileUpload.js
CHANGED
|
@@ -1,317 +1,237 @@
|
|
|
1
|
-
import { I as
|
|
1
|
+
import { defineComponent as H, useCssModule as q, ref as k, inject as K, useAttrs as Q, computed as g, openBlock as n, createElementBlock as i, normalizeClass as d, unref as l, createVNode as w, withModifiers as c, withCtx as I, renderSlot as S, createTextVNode as N, toDisplayString as p, createElementVNode as v, Fragment as U, createBlock as W, createCommentVNode as R, renderList as Z, withDirectives as ee, mergeProps as te, vShow as le } from "vue";
|
|
2
|
+
import se from "@leaflink/snitch";
|
|
3
|
+
import { I as ne } from "./index-79ce320f.js";
|
|
2
4
|
import { t as u } from "./locale.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { _ as P } from "./_plugin-vue_export-helper-dad06003.js";
|
|
5
|
+
import D from "./Button.js";
|
|
6
|
+
import oe from "./Icon.js";
|
|
7
|
+
import { _ as ae } from "./_plugin-vue_export-helper-dad06003.js";
|
|
7
8
|
import "lodash-es/get";
|
|
8
9
|
import "./Button.vue_used_vue_type_style_index_0_lang.module-63d31dc0.js";
|
|
9
10
|
import "lodash-es/uniqueId";
|
|
10
11
|
import "./Icon.vue_used_vue_type_style_index_0_lang.module-eb359559.js";
|
|
11
|
-
const
|
|
12
|
-
"file-dropbox": "_file-dropbox_19hp2_2",
|
|
13
|
-
"is-dragging": "_is-dragging_19hp2_10",
|
|
14
|
-
"is-disabled": "_is-disabled_19hp2_19",
|
|
15
|
-
"upload-icon": "_upload-icon_19hp2_24",
|
|
16
|
-
"remove-button": "_remove-button_19hp2_29",
|
|
17
|
-
button: A
|
|
18
|
-
}, E = Object.freeze({
|
|
12
|
+
const F = {
|
|
19
13
|
CSV: {
|
|
20
|
-
ACCEPTS: ["text/csv"],
|
|
21
14
|
EXTENSION: ["csv"],
|
|
22
15
|
MIME_TYPES: ["text/csv", "application/octet-stream", "application/vnd.ms-excel"],
|
|
23
16
|
ILLUSTRATION: "csv"
|
|
24
17
|
},
|
|
25
18
|
PDF: {
|
|
26
|
-
ACCEPTS: ["application/pdf"],
|
|
27
19
|
EXTENSION: ["pdf"],
|
|
28
20
|
MIME_TYPES: ["application/pdf"],
|
|
29
21
|
ILLUSTRATION: "pdf"
|
|
30
22
|
},
|
|
31
23
|
PNG: {
|
|
32
|
-
ACCEPTS: ["image/png"],
|
|
33
24
|
EXTENSION: ["png"],
|
|
34
25
|
MIME_TYPES: ["image/png"],
|
|
35
26
|
ILLUSTRATION: "image"
|
|
36
27
|
},
|
|
37
28
|
JPEG: {
|
|
38
|
-
ACCEPTS: ["image/jpeg"],
|
|
39
29
|
EXTENSION: ["jpg", "jpeg"],
|
|
40
30
|
MIME_TYPES: ["image/jpeg"],
|
|
41
31
|
ILLUSTRATION: "image"
|
|
42
32
|
},
|
|
43
33
|
DOC: {
|
|
44
|
-
ACCEPTS: ["application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
|
|
45
34
|
EXTENSION: ["doc", "docx"],
|
|
46
35
|
MIME_TYPES: ["application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
|
|
47
36
|
ILLUSTRATION: "document"
|
|
48
37
|
},
|
|
49
38
|
XLS: {
|
|
50
|
-
ACCEPTS: ["application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
|
|
51
39
|
EXTENSION: ["xls", "xlsx"],
|
|
52
40
|
MIME_TYPES: ["application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
|
|
53
41
|
ILLUSTRATION: "csv"
|
|
54
42
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"ll-button": I,
|
|
63
|
-
InlineSvg: D
|
|
64
|
-
},
|
|
65
|
-
inject: ["stashOptions"],
|
|
66
|
-
inheritAttrs: !1,
|
|
43
|
+
};
|
|
44
|
+
var h = /* @__PURE__ */ ((f) => (f.Dense = "dense", f.Standard = "standard", f))(h || {});
|
|
45
|
+
const ie = { key: 0 }, re = ["onDragover", "onDrop", "onDragleave"], de = { class: "tw-text-ice-900" }, ce = {
|
|
46
|
+
key: 0,
|
|
47
|
+
class: "tw-mt-6 tw-text-center tw-text-xs tw-text-ice-700"
|
|
48
|
+
}, pe = ["disabled", "accept", "multiple"], ue = /* @__PURE__ */ H({
|
|
49
|
+
__name: "FileUpload",
|
|
67
50
|
props: {
|
|
68
|
-
files: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*/
|
|
75
|
-
fileTypes: {
|
|
76
|
-
type: Array,
|
|
77
|
-
default: () => Object.keys(E)
|
|
78
|
-
},
|
|
79
|
-
/**
|
|
80
|
-
* Shows only an upload button
|
|
81
|
-
*/
|
|
82
|
-
buttonOnly: {
|
|
83
|
-
type: Boolean,
|
|
84
|
-
default: !1
|
|
85
|
-
},
|
|
86
|
-
/**
|
|
87
|
-
* Disables the upload button
|
|
88
|
-
*/
|
|
89
|
-
disabled: {
|
|
90
|
-
type: Boolean,
|
|
91
|
-
default: !1
|
|
92
|
-
},
|
|
93
|
-
/**
|
|
94
|
-
* When using the drag and drop feature, hide the icon
|
|
95
|
-
* and display everything on one line.
|
|
96
|
-
*/
|
|
97
|
-
size: {
|
|
98
|
-
type: String,
|
|
99
|
-
default: "standard",
|
|
100
|
-
validator: (e) => Object.values(_).includes(e)
|
|
101
|
-
}
|
|
51
|
+
files: { default: () => [] },
|
|
52
|
+
fileTypes: { default: () => ["CSV", "PDF", "PNG", "JPEG", "DOC", "XLS"] },
|
|
53
|
+
buttonOnly: { type: Boolean, default: !1 },
|
|
54
|
+
multiple: { type: Boolean, default: !1 },
|
|
55
|
+
disabled: { type: Boolean, default: !1 },
|
|
56
|
+
size: { default: "standard" }
|
|
102
57
|
},
|
|
103
58
|
emits: ["file-select", "file-delete", "file-error"],
|
|
104
|
-
setup() {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
};
|
|
108
|
-
},
|
|
109
|
-
data() {
|
|
110
|
-
return {
|
|
111
|
-
isDraggingOver: !1,
|
|
112
|
-
removeText: u("ll.fileUpload.remove"),
|
|
113
|
-
fileUploadUploadFileText: u("ll.fileUpload.uploadFile"),
|
|
114
|
-
fileUploadDragDropFileHereText: u("ll.fileUpload.dragDropFileHere"),
|
|
115
|
-
fileUploadOrText: u("ll.fileUpload.or")
|
|
116
|
-
};
|
|
117
|
-
},
|
|
118
|
-
computed: {
|
|
119
|
-
inputAttrs() {
|
|
120
|
-
const e = { ...this.$attrs };
|
|
59
|
+
setup(f, { emit: E }) {
|
|
60
|
+
const m = f, r = q(), y = k(!1), T = k(), _ = K("stashOptions"), M = Q(), A = g(() => {
|
|
61
|
+
const e = { ...M };
|
|
121
62
|
return delete e["data-test"], delete e.class, delete e.type, delete e.accept, e;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
*/
|
|
126
|
-
acceptedMimeTypes() {
|
|
127
|
-
return this.fileTypes.map((e) => this.fileMeta[e].MIME_TYPES).reduce(this.flattenArray);
|
|
128
|
-
},
|
|
129
|
-
/**
|
|
130
|
-
* @returns {Array} A list of accepted file types
|
|
131
|
-
*/
|
|
132
|
-
acceptedFileExtensions() {
|
|
133
|
-
return this.fileTypes.map((e) => this.fileMeta[e].EXTENSION).reduce(this.flattenArray);
|
|
134
|
-
},
|
|
135
|
-
fileMeta() {
|
|
136
|
-
return E;
|
|
137
|
-
},
|
|
138
|
-
illustrationPath() {
|
|
139
|
-
var e;
|
|
140
|
-
return `${(e = this.stashOptions) == null ? void 0 : e.staticPath}/illustrations/FileUpload/${E[this.fileTypes[0]].ILLUSTRATION}.svg`;
|
|
63
|
+
});
|
|
64
|
+
function O(e, t) {
|
|
65
|
+
return e.concat(t);
|
|
141
66
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const t =
|
|
154
|
-
|
|
155
|
-
},
|
|
156
|
-
handleDragEnter() {
|
|
157
|
-
this.isDraggingOver = !0;
|
|
158
|
-
},
|
|
159
|
-
handleDragLeave() {
|
|
160
|
-
this.isDraggingOver = !1;
|
|
161
|
-
},
|
|
162
|
-
/**
|
|
163
|
-
* Sets file to dropped file if it is proper file type
|
|
164
|
-
* @param {Object} event - file select event that contains file
|
|
165
|
-
*/
|
|
166
|
-
async handleDropFile(e) {
|
|
167
|
-
if (this.disabled)
|
|
168
|
-
return;
|
|
169
|
-
const t = [...e.dataTransfer.files];
|
|
170
|
-
if (this.isDraggingOver = !1, this.acceptedMimeTypes.length)
|
|
171
|
-
try {
|
|
172
|
-
if (!(await Promise.all(t.map((l) => this.readMimeType(l)))).every((l) => this.acceptedMimeTypes.includes(l)))
|
|
173
|
-
throw new Error("One or more files contains an unacceptable mime type.");
|
|
174
|
-
if (!t.every((l) => {
|
|
175
|
-
const m = l.name.split(".").pop();
|
|
176
|
-
return this.acceptedFileExtensions.includes(m);
|
|
177
|
-
}))
|
|
178
|
-
throw new Error("One or more files contains an unacceptable extension.");
|
|
179
|
-
this.$emit("file-select", { event: e, files: t });
|
|
180
|
-
} catch (i) {
|
|
181
|
-
this.handleFileError(i);
|
|
182
|
-
}
|
|
183
|
-
else
|
|
184
|
-
this.$emit("file-select", { event: e, files: t });
|
|
185
|
-
},
|
|
186
|
-
handleFileError(e) {
|
|
187
|
-
const t = this.t("ll.fileUpload.errors.incorrectFileType", {
|
|
188
|
-
fileTypes: this.acceptedFileExtensions.join(", ")
|
|
67
|
+
const b = g(() => m.fileTypes.map((e) => F[e].MIME_TYPES).reduce(O)), C = g(() => m.fileTypes.map((e) => F[e].EXTENSION).reduce(O)), X = g(() => `${_ == null ? void 0 : _.staticPath}/illustrations/FileUpload/${F[m.fileTypes[0]].ILLUSTRATION}.svg`);
|
|
68
|
+
function L() {
|
|
69
|
+
T.value && (T.value.value = "", T.value.click());
|
|
70
|
+
}
|
|
71
|
+
function Y() {
|
|
72
|
+
y.value = !0;
|
|
73
|
+
}
|
|
74
|
+
function $() {
|
|
75
|
+
y.value = !1;
|
|
76
|
+
}
|
|
77
|
+
function j(e) {
|
|
78
|
+
const t = u("ll.fileUpload.errors.incorrectFileType", {
|
|
79
|
+
fileTypes: C.value.join(", ")
|
|
189
80
|
});
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
81
|
+
E("file-error", t), se.log(e);
|
|
82
|
+
}
|
|
83
|
+
async function B(e) {
|
|
84
|
+
if (!b.value.length)
|
|
85
|
+
return !0;
|
|
86
|
+
const t = await Promise.all(e.map((a) => J(a)));
|
|
87
|
+
if (!(!!t.length && t.every((a) => b.value.includes(a))))
|
|
88
|
+
throw new Error("One or more files contains an unacceptable mime type.");
|
|
89
|
+
if (!e.every((a) => {
|
|
90
|
+
const P = a.name.split(".").pop();
|
|
91
|
+
return P && C.value.includes(P);
|
|
92
|
+
}))
|
|
93
|
+
throw new Error("One or more files contains an unacceptable extension.");
|
|
94
|
+
return !0;
|
|
95
|
+
}
|
|
96
|
+
async function x(e) {
|
|
97
|
+
try {
|
|
98
|
+
await B(e), E("file-select", { files: e });
|
|
99
|
+
} catch (t) {
|
|
100
|
+
j(t);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function V(e) {
|
|
104
|
+
var s;
|
|
105
|
+
const t = [...((s = e.target) == null ? void 0 : s.files) || []];
|
|
106
|
+
x(t);
|
|
107
|
+
}
|
|
108
|
+
function z(e) {
|
|
109
|
+
var s;
|
|
110
|
+
if (m.disabled)
|
|
111
|
+
return;
|
|
112
|
+
const t = [...((s = e.dataTransfer) == null ? void 0 : s.files) || []];
|
|
113
|
+
return y.value = !1, x(t);
|
|
114
|
+
}
|
|
115
|
+
function G(e) {
|
|
116
|
+
E("file-delete", e);
|
|
117
|
+
}
|
|
118
|
+
function J(e) {
|
|
119
|
+
return new Promise((t, s) => {
|
|
202
120
|
if (e.type)
|
|
203
121
|
return t(e.type);
|
|
204
122
|
if (window.FileReader) {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
const a =
|
|
123
|
+
const o = new FileReader();
|
|
124
|
+
o.onload = () => {
|
|
125
|
+
const a = o.result && o.result.match(/[^:]\w+\/[\w-+\d.]+(?=;|,)/) ? o.result.match(/[^:]\w+\/[\w-+\d.]+(?=;|,)/)[0] : "";
|
|
208
126
|
t(a);
|
|
209
|
-
},
|
|
127
|
+
}, o.readAsDataURL(e);
|
|
210
128
|
} else
|
|
211
|
-
|
|
129
|
+
s(new Error("Failed to read file."));
|
|
212
130
|
});
|
|
213
|
-
},
|
|
214
|
-
flattenArray(e, t) {
|
|
215
|
-
return e.concat(t);
|
|
216
131
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
class: "tw-mt-6 tw-text-center tw-text-xs tw-text-ice-700"
|
|
221
|
-
}, Y = ["accept", "multiple"];
|
|
222
|
-
function B(e, t, i, n, a, l) {
|
|
223
|
-
const m = g("ll-button"), b = g("InlineSvg"), x = g("ll-icon");
|
|
224
|
-
return r(), o("div", {
|
|
225
|
-
class: d(e.$attrs.class),
|
|
226
|
-
"data-test": e.$attrs["data-test"]
|
|
227
|
-
}, [
|
|
228
|
-
i.buttonOnly ? (r(), o("div", z, [
|
|
229
|
-
h(m, {
|
|
230
|
-
secondary: "",
|
|
231
|
-
type: "button",
|
|
232
|
-
disabled: i.disabled || null,
|
|
233
|
-
onClick: c(l.openFileDialog, ["stop", "prevent"])
|
|
234
|
-
}, {
|
|
235
|
-
default: y(() => [
|
|
236
|
-
T(p(a.fileUploadUploadFileText), 1)
|
|
237
|
-
]),
|
|
238
|
-
_: 1
|
|
239
|
-
}, 8, ["disabled", "onClick"])
|
|
240
|
-
])) : (r(), o("div", {
|
|
241
|
-
key: 1,
|
|
242
|
-
class: d(["tw-rounded tw-p-6", [e.$style["file-dropbox"], a.isDraggingOver && e.$style["is-dragging"], i.disabled && e.$style["is-disabled"]]]),
|
|
243
|
-
onDragover: t[0] || (t[0] = c((...s) => l.handleDragEnter && l.handleDragEnter(...s), ["prevent"])),
|
|
244
|
-
onDrop: t[1] || (t[1] = c((...s) => l.handleDropFile && l.handleDropFile(...s), ["prevent"])),
|
|
245
|
-
onDragleave: t[2] || (t[2] = c((...s) => l.handleDragLeave && l.handleDragLeave(...s), ["prevent"]))
|
|
132
|
+
return (e, t) => (n(), i("div", {
|
|
133
|
+
class: d(["stash-file-upload", l(M).class]),
|
|
134
|
+
"data-test": "stash-file-upload"
|
|
246
135
|
}, [
|
|
247
|
-
|
|
248
|
-
|
|
136
|
+
e.buttonOnly ? (n(), i("div", ie, [
|
|
137
|
+
w(D, {
|
|
138
|
+
secondary: "",
|
|
139
|
+
type: "button",
|
|
140
|
+
disabled: e.disabled || null,
|
|
141
|
+
onClick: c(L, ["stop", "prevent"])
|
|
142
|
+
}, {
|
|
143
|
+
default: I(() => [
|
|
144
|
+
S(e.$slots, "submitText", {}, () => [
|
|
145
|
+
N(p(l(u)("ll.fileUpload.uploadFile")), 1)
|
|
146
|
+
])
|
|
147
|
+
]),
|
|
148
|
+
_: 3
|
|
149
|
+
}, 8, ["disabled", "onClick"])
|
|
150
|
+
])) : (n(), i("div", {
|
|
151
|
+
key: 1,
|
|
152
|
+
class: d(["tw-rounded tw-p-6", [l(r)["file-dropbox"], y.value && l(r)["is-dragging"], e.disabled && l(r)["is-disabled"]]]),
|
|
153
|
+
onDragover: c(Y, ["prevent"]),
|
|
154
|
+
onDrop: c(z, ["prevent"]),
|
|
155
|
+
onDragleave: c($, ["prevent"])
|
|
249
156
|
}, [
|
|
250
|
-
|
|
251
|
-
|
|
157
|
+
v("div", {
|
|
158
|
+
class: d(["tw-flex tw-flex-col tw-items-center tw-justify-center tw-text-center", [{ "tw-items-center md:tw-flex-row": e.size === l(h).Dense }]])
|
|
252
159
|
}, [
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
160
|
+
e.files.length ? (n(!0), i(U, { key: 1 }, Z(e.files, (s) => (n(), i("div", {
|
|
161
|
+
key: s.name
|
|
162
|
+
}, [
|
|
163
|
+
w(oe, { name: "file" }),
|
|
164
|
+
v("span", null, p(s.name), 1),
|
|
165
|
+
w(D, {
|
|
166
|
+
class: d([l(r)["remove-button"], l(r).button]),
|
|
167
|
+
onClick: c((o) => G(s), ["stop", "prevent"])
|
|
168
|
+
}, {
|
|
169
|
+
default: I(() => [
|
|
170
|
+
N(p(l(u)("ll.fileUpload.remove")), 1)
|
|
171
|
+
]),
|
|
172
|
+
_: 2
|
|
173
|
+
}, 1032, ["class", "onClick"])
|
|
174
|
+
]))), 128)) : (n(), i(U, { key: 0 }, [
|
|
175
|
+
e.size !== l(h).Dense ? (n(), W(l(ne), {
|
|
176
|
+
key: 0,
|
|
177
|
+
src: X.value,
|
|
178
|
+
name: "file",
|
|
179
|
+
width: "84",
|
|
180
|
+
height: "96"
|
|
181
|
+
}, null, 8, ["src"])) : R("", !0),
|
|
182
|
+
v("span", de, p(l(u)("ll.fileUpload.dragDropFileHere")), 1),
|
|
183
|
+
v("span", {
|
|
184
|
+
class: d(
|
|
185
|
+
e.size === l(h).Dense ? "md:tw-ml-1.5 md:tw-mr-3 md:tw-my-0 tw-my-1.5 tw-text-ice-900" : "tw-mt-1.5 tw-my-1.5"
|
|
186
|
+
)
|
|
187
|
+
}, p(l(u)("ll.fileUpload.or")), 3),
|
|
188
|
+
w(D, {
|
|
189
|
+
class: d(["tw-mt-1.5", l(r)["file-select-button"]]),
|
|
190
|
+
secondary: "",
|
|
191
|
+
type: "button",
|
|
192
|
+
disabled: e.disabled,
|
|
193
|
+
onClick: c(L, ["stop", "prevent"])
|
|
194
|
+
}, {
|
|
195
|
+
default: I(() => [
|
|
196
|
+
S(e.$slots, "submitText", {}, () => [
|
|
197
|
+
N(p(l(u)("ll.fileUpload.uploadFile")), 1)
|
|
198
|
+
])
|
|
199
|
+
]),
|
|
200
|
+
_: 3
|
|
201
|
+
}, 8, ["class", "disabled", "onClick"])
|
|
202
|
+
], 64))
|
|
203
|
+
], 2),
|
|
204
|
+
e.$slots.hint && !e.files.length ? (n(), i("div", ce, [
|
|
205
|
+
S(e.$slots, "hint")
|
|
206
|
+
])) : R("", !0)
|
|
207
|
+
], 42, re)),
|
|
208
|
+
ee(v("input", te(A.value, {
|
|
209
|
+
ref_key: "fileUploadRef",
|
|
210
|
+
ref: T,
|
|
211
|
+
"data-test": "stash-file-upload|input",
|
|
212
|
+
type: "file",
|
|
213
|
+
disabled: e.disabled,
|
|
214
|
+
accept: b.value.join(","),
|
|
215
|
+
multiple: m.multiple,
|
|
216
|
+
onChange: V
|
|
217
|
+
}), null, 16, pe), [
|
|
218
|
+
[le, !1]
|
|
219
|
+
])
|
|
220
|
+
], 2));
|
|
221
|
+
}
|
|
222
|
+
}), fe = "_button_19hp2_29", me = {
|
|
223
|
+
"file-dropbox": "_file-dropbox_19hp2_2",
|
|
224
|
+
"is-dragging": "_is-dragging_19hp2_10",
|
|
225
|
+
"is-disabled": "_is-disabled_19hp2_19",
|
|
226
|
+
"upload-icon": "_upload-icon_19hp2_24",
|
|
227
|
+
"remove-button": "_remove-button_19hp2_29",
|
|
228
|
+
button: fe
|
|
229
|
+
}, ve = {
|
|
230
|
+
$style: me
|
|
231
|
+
}, De = /* @__PURE__ */ ae(ue, [["__cssModules", ve]]);
|
|
312
232
|
export {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
233
|
+
F as FILE_TYPES,
|
|
234
|
+
h as FileUploadSizes,
|
|
235
|
+
De as default
|
|
316
236
|
};
|
|
317
237
|
//# sourceMappingURL=FileUpload.js.map
|
package/dist/FileUpload.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileUpload.js","sources":["../src/components/FileUpload/FileUpload.vue"],"sourcesContent":["<script>\n import InlineSvg from 'vue-inline-svg';\n\n import { t } from '../../locale';\n import Button from '../Button/Button.vue';\n import Icon from '../Icon/Icon.vue';\n\n export const FILE_TYPES = Object.freeze({\n CSV: {\n ACCEPTS: ['text/csv'],\n EXTENSION: ['csv'],\n MIME_TYPES: ['text/csv', 'application/octet-stream', 'application/vnd.ms-excel'],\n ILLUSTRATION: 'csv',\n },\n PDF: {\n ACCEPTS: ['application/pdf'],\n EXTENSION: ['pdf'],\n MIME_TYPES: ['application/pdf'],\n ILLUSTRATION: 'pdf',\n },\n PNG: {\n ACCEPTS: ['image/png'],\n EXTENSION: ['png'],\n MIME_TYPES: ['image/png'],\n ILLUSTRATION: 'image',\n },\n JPEG: {\n ACCEPTS: ['image/jpeg'],\n EXTENSION: ['jpg', 'jpeg'],\n MIME_TYPES: ['image/jpeg'],\n ILLUSTRATION: 'image',\n },\n DOC: {\n ACCEPTS: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],\n EXTENSION: ['doc', 'docx'],\n MIME_TYPES: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],\n ILLUSTRATION: 'document',\n },\n XLS: {\n ACCEPTS: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],\n EXTENSION: ['xls', 'xlsx'],\n MIME_TYPES: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],\n ILLUSTRATION: 'csv',\n },\n });\n\n // TODO: convert to enum (typescript)\n export const Sizes = Object.freeze({\n Dense: 'dense',\n Standard: 'standard',\n });\n\n export default {\n name: 'll-file-upload',\n\n components: {\n 'll-icon': Icon,\n 'll-button': Button,\n InlineSvg,\n },\n\n inject: ['stashOptions'],\n\n inheritAttrs: false,\n\n props: {\n files: {\n type: Array,\n default: () => [],\n },\n\n /**\n * The file types accepted by the input\n */\n fileTypes: {\n type: Array,\n default: () => Object.keys(FILE_TYPES),\n },\n\n /**\n * Shows only an upload button\n */\n buttonOnly: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Disables the upload button\n */\n disabled: {\n type: Boolean,\n default: false,\n },\n\n /**\n * When using the drag and drop feature, hide the icon\n * and display everything on one line.\n */\n size: {\n type: String,\n default: 'standard',\n validator: (value) => Object.values(Sizes).includes(value),\n },\n },\n\n emits: ['file-select', 'file-delete', 'file-error'],\n\n setup() {\n return {\n Sizes,\n };\n },\n\n data() {\n return {\n isDraggingOver: false,\n removeText: t('ll.fileUpload.remove'),\n fileUploadUploadFileText: t('ll.fileUpload.uploadFile'),\n fileUploadDragDropFileHereText: t('ll.fileUpload.dragDropFileHere'),\n fileUploadOrText: t('ll.fileUpload.or'),\n };\n },\n\n computed: {\n inputAttrs() {\n const attrs = { ...this.$attrs };\n\n delete attrs['data-test'];\n delete attrs.class;\n delete attrs.type;\n delete attrs.accept;\n\n return attrs;\n },\n\n /**\n * @returns {Array} A list of accepted file types\n */\n acceptedMimeTypes() {\n return this.fileTypes.map((fileType) => this.fileMeta[fileType].MIME_TYPES).reduce(this.flattenArray);\n },\n\n /**\n * @returns {Array} A list of accepted file types\n */\n acceptedFileExtensions() {\n return this.fileTypes.map((fileType) => this.fileMeta[fileType].EXTENSION).reduce(this.flattenArray);\n },\n\n fileMeta() {\n return FILE_TYPES;\n },\n\n illustrationPath() {\n return `${this.stashOptions?.staticPath}/illustrations/FileUpload/${\n FILE_TYPES[this.fileTypes[0]].ILLUSTRATION\n }.svg`;\n },\n },\n\n methods: {\n openFileDialog() {\n if (this.$refs.fileUpload) {\n this.$refs.fileUpload.value = '';\n this.$refs.fileUpload.click();\n }\n },\n\n /**\n * Sets file(s) to selected file(s) from dialogue\n * @param {Object} event - file select event that contains file(s)\n * @returns {Array} An array of files\n */\n handleFileInput(event) {\n const files = [...event.target.files];\n\n this.$emit('file-select', { event, files });\n },\n\n handleDragEnter() {\n this.isDraggingOver = true;\n },\n\n handleDragLeave() {\n this.isDraggingOver = false;\n },\n\n /**\n * Sets file to dropped file if it is proper file type\n * @param {Object} event - file select event that contains file\n */\n async handleDropFile(event) {\n if (this.disabled) {\n return;\n }\n\n const files = [...event.dataTransfer.files];\n\n this.isDraggingOver = false;\n\n if (this.acceptedMimeTypes.length) {\n try {\n const mimeTypePromises = await Promise.all(files.map((file) => this.readMimeType(file)));\n const allCorrectMimeTypes = mimeTypePromises.every((mimeType) => this.acceptedMimeTypes.includes(mimeType));\n\n if (!allCorrectMimeTypes) {\n throw new Error('One or more files contains an unacceptable mime type.');\n }\n\n const allCorrectFileExtensions = files.every((file) => {\n const extension = file.name.split('.').pop();\n\n return this.acceptedFileExtensions.includes(extension);\n });\n\n if (!allCorrectFileExtensions) {\n throw new Error('One or more files contains an unacceptable extension.');\n }\n\n this.$emit('file-select', { event, files });\n } catch (error) {\n this.handleFileError(error);\n }\n } else {\n this.$emit('file-select', { event, files });\n }\n },\n\n handleFileError(error) {\n const message = this.t('ll.fileUpload.errors.incorrectFileType', {\n fileTypes: this.acceptedFileExtensions.join(', '),\n });\n\n if (this.$attrs['file-error']) {\n this.$emit('file-error', message);\n } else {\n this.$notify.warning(message);\n }\n\n throw error;\n },\n\n handleFileDelete(file) {\n this.$emit('file-delete', file);\n },\n\n /**\n * Check for the mime type on the uploaded File object\n * Otherwise load the file and attempt to read it\n * @param file The Uploaded File object\n */\n readMimeType(file) {\n return new Promise((resolve, reject) => {\n if (file.type) {\n return resolve(file.type);\n } else if (window.FileReader) {\n const fileReader = new FileReader();\n\n fileReader.onload = () => {\n const mimeType = fileReader.result.match(/[^:]\\w+\\/[\\w-+\\d.]+(?=;|,)/)\n ? fileReader.result.match(/[^:]\\w+\\/[\\w-+\\d.]+(?=;|,)/)[0]\n : '';\n\n resolve(mimeType);\n };\n\n fileReader.readAsDataURL(file);\n } else {\n reject(new Error('Failed to read file.'));\n }\n });\n },\n\n flattenArray(a, b) {\n return a.concat(b);\n },\n },\n };\n</script>\n\n<template>\n <div :class=\"$attrs.class\" :data-test=\"$attrs['data-test']\">\n <div v-if=\"buttonOnly\">\n <ll-button secondary type=\"button\" :disabled=\"disabled || null\" @click.stop.prevent=\"openFileDialog\">\n {{ fileUploadUploadFileText }}\n </ll-button>\n </div>\n <div\n v-else\n class=\"tw-rounded tw-p-6\"\n :class=\"[$style['file-dropbox'], isDraggingOver && $style['is-dragging'], disabled && $style['is-disabled']]\"\n @dragover.prevent=\"handleDragEnter\"\n @drop.prevent=\"handleDropFile\"\n @dragleave.prevent=\"handleDragLeave\"\n >\n <div\n class=\"tw-flex tw-flex-col tw-items-center tw-justify-center tw-text-center\"\n :class=\"[{ 'md:flex-row tw-items-center': size === Sizes.Dense }]\"\n >\n <template v-if=\"!files.length\">\n <InlineSvg v-if=\"size !== Sizes.Dense\" :src=\"illustrationPath\" name=\"file\" width=\"84\" height=\"96\" />\n <span class=\"tw-text-ice-900\">\n {{ fileUploadDragDropFileHereText }}\n </span>\n <span\n :class=\"\n size === Sizes.Dense\n ? 'md:tw-ml-1.5 md:tw-mr-3 md:tw-my-0 tw-my-1.5 tw-text-ice-900'\n : 'tw-mt-1.5 tw-my-1.5'\n \"\n >\n {{ fileUploadOrText }}\n </span>\n <ll-button\n class=\"tw-mt-1.5\"\n secondary\n type=\"button\"\n :class=\"$style['file-select-button']\"\n :disabled=\"disabled\"\n @click.stop.prevent=\"openFileDialog\"\n >\n <!-- @slot for custom submit text -->\n <slot name=\"submitText\">{{ fileUploadUploadFileText }}</slot>\n </ll-button>\n </template>\n <template v-else>\n <div v-for=\"file in files\" :key=\"file.name\">\n <ll-icon name=\"file\" />\n <span>{{ file.name }}</span>\n <ll-button\n :class=\"[$style['remove-button'], $style['button']]\"\n @click.stop.prevent=\"handleFileDelete(file)\"\n >\n {{ removeText }}\n </ll-button>\n </div>\n </template>\n </div>\n <div v-if=\"$slots.hint && !files.length\" class=\"tw-mt-6 tw-text-center tw-text-xs tw-text-ice-700\">\n <!-- @slot for displaying helpful text and/or links -->\n <slot name=\"hint\"></slot>\n </div>\n </div>\n <input\n v-show=\"false\"\n v-bind=\"inputAttrs\"\n ref=\"fileUpload\"\n type=\"file\"\n :accept=\"fileTypes.map((fileType) => fileMeta[fileType].ACCEPTS).reduce(flattenArray)\"\n :multiple=\"$attrs['multiple']\"\n @change=\"handleFileInput($event)\"\n />\n </div>\n</template>\n\n<style module>\n .file-dropbox {\n background: var(--color-ice-200);\n background-image: url(\"data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='4' ry='4' stroke='%23C5C9D4FF' stroke-width='1' stroke-dasharray='5 %2c 5' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n border: theme('borderWidth.DEFAULT') solid var(--color-ice-500);\n border-color: transparent;\n }\n\n .is-dragging {\n background-image: none;\n border-color: var(--color-ice-500);\n\n & > * {\n pointer-events: none;\n }\n }\n\n .is-disabled {\n cursor: no-drop;\n }\n\n /* Constrain the upload icon for drag/drop to the required size */\n .upload-icon {\n height: 98px;\n width: 84px;\n }\n\n .remove-button.button {\n background: transparent;\n border: none;\n color: var(--color-red-500);\n\n &:hover {\n background: transparent;\n border: none;\n }\n }\n</style>\n"],"names":["FILE_TYPES","Sizes","_sfc_main","Icon","Button","InlineSvg","value","t","attrs","fileType","_a","event","files","file","mimeType","extension","error","message","resolve","reject","fileReader","a","b","_hoisted_3","_createElementBlock","_normalizeClass","_ctx","$props","_hoisted_2","_createVNode","_component_ll_button","$options","$data","args","_createElementVNode","$setup","_Fragment","_renderList","_component_ll_icon","_toDisplayString","_withModifiers","$event","_createBlock","_component_InlineSvg","_renderSlot","_openBlock","_hoisted_4","_mergeProps","_cache"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileUpload.js","sources":["../src/components/FileUpload/FileUpload.constants.ts","../src/components/FileUpload/FileUpload.vue"],"sourcesContent":["export const FILE_TYPES = {\n CSV: {\n EXTENSION: ['csv'],\n MIME_TYPES: ['text/csv', 'application/octet-stream', 'application/vnd.ms-excel'],\n ILLUSTRATION: 'csv',\n },\n PDF: {\n EXTENSION: ['pdf'],\n MIME_TYPES: ['application/pdf'],\n ILLUSTRATION: 'pdf',\n },\n PNG: {\n EXTENSION: ['png'],\n MIME_TYPES: ['image/png'],\n ILLUSTRATION: 'image',\n },\n JPEG: {\n EXTENSION: ['jpg', 'jpeg'],\n MIME_TYPES: ['image/jpeg'],\n ILLUSTRATION: 'image',\n },\n DOC: {\n EXTENSION: ['doc', 'docx'],\n MIME_TYPES: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],\n ILLUSTRATION: 'document',\n },\n XLS: {\n EXTENSION: ['xls', 'xlsx'],\n MIME_TYPES: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],\n ILLUSTRATION: 'csv',\n },\n};\n\nexport enum FileUploadSizes {\n Dense = 'dense',\n Standard = 'standard',\n}\n\nexport type FileUploadSize = `${FileUploadSizes}`;\n","<script lang=\"ts\">\n export * from './FileUpload.constants';\n</script>\n\n<script setup lang=\"ts\">\n import logger from '@leaflink/snitch';\n import { computed, inject, ref, useAttrs, useCssModule } from 'vue';\n import InlineSvg from 'vue-inline-svg';\n\n import { StashProvideState } from '../../../types/misc';\n import { t } from '../../locale';\n import Button from '../Button/Button.vue';\n import Icon from '../Icon/Icon.vue';\n import { FILE_TYPES, FileUploadSize, FileUploadSizes } from './FileUpload.constants';\n\n export type FileType = 'CSV' | 'PDF' | 'PNG' | 'JPEG' | 'DOC' | 'XLS';\n\n export interface FileUploadProps {\n /**\n * Files to display in the component\n */\n files?: File[];\n\n /**\n * Accepted file types\n */\n fileTypes?: FileType[];\n\n /**\n * Should display only the button\n */\n buttonOnly?: boolean;\n\n /**\n * Allows upload of multiple files\n */\n multiple?: boolean;\n\n /**\n * Is the input disabled\n */\n disabled?: boolean;\n\n /**\n * Component size\n */\n size?: FileUploadSize;\n }\n\n const props = withDefaults(defineProps<FileUploadProps>(), {\n files: () => [],\n fileTypes: () => ['CSV', 'PDF', 'PNG', 'JPEG', 'DOC', 'XLS'],\n buttonOnly: false,\n disabled: false,\n multiple: false,\n size: 'standard',\n });\n\n const classes = useCssModule();\n\n const emit =\n defineEmits<{\n (e: 'file-select', { files }: { files: FileUploadProps['files'] }): void;\n (e: 'file-delete', file: File): void;\n (e: 'file-error', message: string): void;\n }>();\n\n const isDraggingOver = ref(false);\n const fileUploadRef = ref<HTMLInputElement>();\n\n const stashOptions = inject<StashProvideState>('stashOptions');\n const attributes = useAttrs();\n\n const inputAttrs = computed(() => {\n const attrs = { ...attributes };\n\n delete attrs['data-test'];\n delete attrs.class;\n delete attrs.type;\n delete attrs.accept;\n\n return attrs;\n });\n\n function concatArraysToFirst(a: any[], b: any[]) {\n return a.concat(b);\n }\n\n const acceptedMimeTypes = computed(() => {\n return props.fileTypes.map((fileType) => FILE_TYPES[fileType].MIME_TYPES).reduce(concatArraysToFirst);\n });\n\n const acceptedFileExtensions = computed(() => {\n return props.fileTypes.map((fileType) => FILE_TYPES[fileType].EXTENSION).reduce(concatArraysToFirst);\n });\n\n const illustrationPath = computed(() => {\n return `${stashOptions?.staticPath}/illustrations/FileUpload/${FILE_TYPES[props.fileTypes[0]].ILLUSTRATION}.svg`;\n });\n\n function openFileDialog() {\n if (fileUploadRef.value) {\n fileUploadRef.value.value = '';\n fileUploadRef.value.click();\n }\n }\n\n function handleDragEnter() {\n isDraggingOver.value = true;\n }\n\n function handleDragLeave() {\n isDraggingOver.value = false;\n }\n\n function handleFileError(error: Error) {\n const message = t('ll.fileUpload.errors.incorrectFileType', {\n fileTypes: acceptedFileExtensions.value.join(', '),\n });\n\n emit('file-error', message);\n\n logger.log(error);\n }\n\n async function areFileTypesAccepted(files: File[]) {\n if (!acceptedMimeTypes.value.length) return true;\n\n const mimeTypes = await Promise.all(files.map((file) => readMimeType(file)));\n\n const allCorrectMimeTypes =\n !!mimeTypes.length && mimeTypes.every((mimeType) => acceptedMimeTypes.value.includes(mimeType));\n\n if (!allCorrectMimeTypes) {\n throw new Error('One or more files contains an unacceptable mime type.');\n }\n\n const allCorrectFileExtensions = files.every((file) => {\n const extension = file.name.split('.').pop();\n\n return extension && acceptedFileExtensions.value.includes(extension);\n });\n\n if (!allCorrectFileExtensions) {\n throw new Error('One or more files contains an unacceptable extension.');\n }\n\n return true;\n }\n\n async function processFiles(files: File[]) {\n try {\n await areFileTypesAccepted(files);\n\n emit('file-select', { files });\n } catch (error) {\n handleFileError(error as Error);\n }\n }\n\n /**\n * Sets file(s) to selected file(s) from dialogue\n * @param {Object} event - file select event that contains file(s)\n * @returns {Array} An array of files\n */\n function handleFileInput(event: Event) {\n const files = [...((event.target as HTMLInputElement)?.files || [])];\n\n processFiles(files);\n }\n\n /**\n * Sets file to dropped file if it is proper file type\n * @param {Object} event - file select event that contains file\n */\n function handleDropFile(event: DragEvent) {\n if (props.disabled) {\n return;\n }\n\n const files = [...(event.dataTransfer?.files || [])];\n\n isDraggingOver.value = false;\n\n return processFiles(files);\n }\n\n function handleFileDelete(file: File) {\n emit('file-delete', file);\n }\n\n function readMimeType(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n if (file.type) {\n return resolve(file.type);\n } else if (window.FileReader) {\n const fileReader = new FileReader();\n\n fileReader.onload = () => {\n const mimeType =\n fileReader.result && (fileReader.result as string).match(/[^:]\\w+\\/[\\w-+\\d.]+(?=;|,)/)\n ? ((fileReader.result as string).match(/[^:]\\w+\\/[\\w-+\\d.]+(?=;|,)/) as string[])[0]\n : '';\n\n resolve(mimeType);\n };\n\n fileReader.readAsDataURL(file);\n } else {\n reject(new Error('Failed to read file.'));\n }\n });\n }\n</script>\n\n<template>\n <div class=\"stash-file-upload\" :class=\"attributes.class\" data-test=\"stash-file-upload\">\n <div v-if=\"buttonOnly\">\n <Button secondary type=\"button\" :disabled=\"disabled || null\" @click.stop.prevent=\"openFileDialog\">\n <slot name=\"submitText\">\n {{ t('ll.fileUpload.uploadFile') }}\n </slot>\n </Button>\n </div>\n <div\n v-else\n class=\"tw-rounded tw-p-6\"\n :class=\"[classes['file-dropbox'], isDraggingOver && classes['is-dragging'], disabled && classes['is-disabled']]\"\n @dragover.prevent=\"handleDragEnter\"\n @drop.prevent=\"handleDropFile\"\n @dragleave.prevent=\"handleDragLeave\"\n >\n <div\n class=\"tw-flex tw-flex-col tw-items-center tw-justify-center tw-text-center\"\n :class=\"[{ 'tw-items-center md:tw-flex-row': size === FileUploadSizes.Dense }]\"\n >\n <template v-if=\"!files.length\">\n <InlineSvg v-if=\"size !== FileUploadSizes.Dense\" :src=\"illustrationPath\" name=\"file\" width=\"84\" height=\"96\" />\n <span class=\"tw-text-ice-900\">\n {{ t('ll.fileUpload.dragDropFileHere') }}\n </span>\n <span\n :class=\"\n size === FileUploadSizes.Dense\n ? 'md:tw-ml-1.5 md:tw-mr-3 md:tw-my-0 tw-my-1.5 tw-text-ice-900'\n : 'tw-mt-1.5 tw-my-1.5'\n \"\n >\n {{ t('ll.fileUpload.or') }}\n </span>\n <Button\n class=\"tw-mt-1.5\"\n secondary\n type=\"button\"\n :class=\"classes['file-select-button']\"\n :disabled=\"disabled\"\n @click.stop.prevent=\"openFileDialog\"\n >\n <!-- @slot for custom submit text -->\n <slot name=\"submitText\">{{ t('ll.fileUpload.uploadFile') }}</slot>\n </Button>\n </template>\n <template v-else>\n <div v-for=\"file in files\" :key=\"file.name\">\n <Icon name=\"file\" />\n <span>{{ file.name }}</span>\n <Button :class=\"[classes['remove-button'], classes['button']]\" @click.stop.prevent=\"handleFileDelete(file)\">\n {{ t('ll.fileUpload.remove') }}\n </Button>\n </div>\n </template>\n </div>\n <div v-if=\"$slots.hint && !files.length\" class=\"tw-mt-6 tw-text-center tw-text-xs tw-text-ice-700\">\n <!-- @slot for displaying helpful text and/or links -->\n <slot name=\"hint\"></slot>\n </div>\n </div>\n <input\n v-show=\"false\"\n v-bind=\"inputAttrs\"\n ref=\"fileUploadRef\"\n data-test=\"stash-file-upload|input\"\n type=\"file\"\n :disabled=\"disabled\"\n :accept=\"acceptedMimeTypes.join(',')\"\n :multiple=\"props.multiple\"\n @change=\"handleFileInput\"\n />\n </div>\n</template>\n\n<style module>\n .file-dropbox {\n background: var(--color-ice-200);\n background-image: url(\"data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='4' ry='4' stroke='%23C5C9D4FF' stroke-width='1' stroke-dasharray='5 %2c 5' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n border: theme('borderWidth.DEFAULT') solid var(--color-ice-500);\n border-color: transparent;\n }\n\n .is-dragging {\n background-image: none;\n border-color: var(--color-ice-500);\n\n & > * {\n pointer-events: none;\n }\n }\n\n .is-disabled {\n cursor: no-drop;\n }\n\n /* Constrain the upload icon for drag/drop to the required size */\n .upload-icon {\n height: 98px;\n width: 84px;\n }\n\n .remove-button.button {\n background: transparent;\n border: none;\n color: var(--color-red-500);\n\n &:hover {\n background: transparent;\n border: none;\n }\n }\n</style>\n"],"names":["FILE_TYPES","FileUploadSizes","classes","useCssModule","isDraggingOver","ref","fileUploadRef","stashOptions","inject","attributes","useAttrs","inputAttrs","computed","attrs","concatArraysToFirst","a","b","acceptedMimeTypes","props","fileType","acceptedFileExtensions","illustrationPath","openFileDialog","handleDragEnter","handleDragLeave","handleFileError","error","message","t","emit","logger","areFileTypesAccepted","files","mimeTypes","file","readMimeType","mimeType","extension","processFiles","handleFileInput","event","_a","handleDropFile","handleFileDelete","resolve","reject","fileReader"],"mappings":"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"}
|