@leaflink/stash 44.4.0 → 44.5.1

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.
@@ -1,317 +1,237 @@
1
- import { I as D } from "./index-79ce320f.js";
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 I from "./Button.js";
4
- import F from "./Icon.js";
5
- import { resolveComponent as g, openBlock as r, createElementBlock as o, normalizeClass as d, createVNode as h, withModifiers as c, withCtx as y, createTextVNode as T, toDisplayString as p, createElementVNode as f, Fragment as v, createBlock as O, createCommentVNode as w, renderSlot as S, renderList as C, withDirectives as U, mergeProps as M, vShow as N } from "vue";
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 A = "_button_19hp2_29", L = {
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
- }), _ = Object.freeze({
56
- Dense: "dense",
57
- Standard: "standard"
58
- }), k = {
59
- name: "ll-file-upload",
60
- components: {
61
- "ll-icon": F,
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
- type: Array,
70
- default: () => []
71
- },
72
- /**
73
- * The file types accepted by the input
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
- return {
106
- Sizes: _
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
- * @returns {Array} A list of accepted file types
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
- methods: {
144
- openFileDialog() {
145
- this.$refs.fileUpload && (this.$refs.fileUpload.value = "", this.$refs.fileUpload.click());
146
- },
147
- /**
148
- * Sets file(s) to selected file(s) from dialogue
149
- * @param {Object} event - file select event that contains file(s)
150
- * @returns {Array} An array of files
151
- */
152
- handleFileInput(e) {
153
- const t = [...e.target.files];
154
- this.$emit("file-select", { event: e, files: t });
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
- throw this.$attrs["file-error"] ? this.$emit("file-error", t) : this.$notify.warning(t), e;
191
- },
192
- handleFileDelete(e) {
193
- this.$emit("file-delete", e);
194
- },
195
- /**
196
- * Check for the mime type on the uploaded File object
197
- * Otherwise load the file and attempt to read it
198
- * @param file The Uploaded File object
199
- */
200
- readMimeType(e) {
201
- return new Promise((t, i) => {
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 n = new FileReader();
206
- n.onload = () => {
207
- const a = n.result.match(/[^:]\w+\/[\w-+\d.]+(?=;|,)/) ? n.result.match(/[^:]\w+\/[\w-+\d.]+(?=;|,)/)[0] : "";
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
- }, n.readAsDataURL(e);
127
+ }, o.readAsDataURL(e);
210
128
  } else
211
- i(new Error("Failed to read file."));
129
+ s(new Error("Failed to read file."));
212
130
  });
213
- },
214
- flattenArray(e, t) {
215
- return e.concat(t);
216
131
  }
217
- }
218
- }, j = ["data-test"], z = { key: 0 }, R = { class: "tw-text-ice-900" }, X = {
219
- key: 0,
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
- f("div", {
248
- class: d(["tw-flex tw-flex-col tw-items-center tw-justify-center tw-text-center", [{ "md:flex-row tw-items-center": i.size === n.Sizes.Dense }]])
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
- i.files.length ? (r(!0), o(v, { key: 1 }, C(i.files, (s) => (r(), o("div", {
251
- key: s.name
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
- h(x, { name: "file" }),
254
- f("span", null, p(s.name), 1),
255
- h(m, {
256
- class: d([e.$style["remove-button"], e.$style.button]),
257
- onClick: c((H) => l.handleFileDelete(s), ["stop", "prevent"])
258
- }, {
259
- default: y(() => [
260
- T(p(a.removeText), 1)
261
- ]),
262
- _: 2
263
- }, 1032, ["class", "onClick"])
264
- ]))), 128)) : (r(), o(v, { key: 0 }, [
265
- i.size !== n.Sizes.Dense ? (r(), O(b, {
266
- key: 0,
267
- src: l.illustrationPath,
268
- name: "file",
269
- width: "84",
270
- height: "96"
271
- }, null, 8, ["src"])) : w("", !0),
272
- f("span", R, p(a.fileUploadDragDropFileHereText), 1),
273
- f("span", {
274
- class: d(
275
- i.size === n.Sizes.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"
276
- )
277
- }, p(a.fileUploadOrText), 3),
278
- h(m, {
279
- class: d(["tw-mt-1.5", e.$style["file-select-button"]]),
280
- secondary: "",
281
- type: "button",
282
- disabled: i.disabled,
283
- onClick: c(l.openFileDialog, ["stop", "prevent"])
284
- }, {
285
- default: y(() => [
286
- S(e.$slots, "submitText", {}, () => [
287
- T(p(a.fileUploadUploadFileText), 1)
288
- ])
289
- ]),
290
- _: 3
291
- }, 8, ["class", "disabled", "onClick"])
292
- ], 64))
293
- ], 2),
294
- e.$slots.hint && !i.files.length ? (r(), o("div", X, [
295
- S(e.$slots, "hint")
296
- ])) : w("", !0)
297
- ], 34)),
298
- U(f("input", M(l.inputAttrs, {
299
- ref: "fileUpload",
300
- type: "file",
301
- accept: i.fileTypes.map((s) => l.fileMeta[s].ACCEPTS).reduce(l.flattenArray),
302
- multiple: e.$attrs.multiple,
303
- onChange: t[3] || (t[3] = (s) => l.handleFileInput(s))
304
- }), null, 16, Y), [
305
- [N, !1]
306
- ])
307
- ], 10, j);
308
- }
309
- const V = {
310
- $style: L
311
- }, le = /* @__PURE__ */ P(k, [["render", B], ["__cssModules", V]]);
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
- E as FILE_TYPES,
314
- _ as Sizes,
315
- le as default
233
+ F as FILE_TYPES,
234
+ h as FileUploadSizes,
235
+ De as default
316
236
  };
317
237
  //# sourceMappingURL=FileUpload.js.map
@@ -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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"}