@vuesimple/vs-upload 3.1.6

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Ashwin K Shenoy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # Vue Simple Upload
2
+
3
+ #### 📁 A simple vue file upload component with drag-and-drop support.
4
+
5
+ A light weight vue plugin built groundup.
6
+
7
+ [![npm](https://img.shields.io/npm/v/@vuesimple/vs-upload.svg)](https://www.npmjs.com/package/@vuesimple/vs-upload)
8
+ [![npm](https://img.shields.io/npm/dt/@vuesimple/vs-upload.svg)](https://img.shields.io/npm/dt/@vuesimple/vs-upload.svg)
9
+ <br />
10
+
11
+ ![forthebadge](https://forthebadge.com/images/badges/made-with-vue.svg)
12
+ ![forthebadge](https://forthebadge.com/images/badges/made-with-javascript.svg)
13
+ ![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)
14
+
15
+ <br />
16
+
17
+ ### 📺 Live Demo
18
+
19
+ Demo: [Link](https://vuesimple.netlify.app)
20
+
21
+ <br />
22
+
23
+ ## Usage
24
+
25
+ ```html
26
+ <template>
27
+ <vs-upload v-model="files" label="Upload a file" multiple />
28
+ </template>
29
+
30
+ <script>
31
+ import VsUpload from '@vuesimple/vs-upload';
32
+
33
+ export default {
34
+ components: { VsUpload },
35
+ data() {
36
+ return { files: [] };
37
+ },
38
+ };
39
+ </script>
40
+ ```
41
+
42
+ <br />
43
+
44
+ ## CDN
45
+
46
+ ```html
47
+ <script src="https://cdn.jsdelivr.net/npm/@vuesimple/vs-upload@<version>/dist/index.min.js"></script>
48
+ ```
49
+
50
+ ```javascript
51
+ // Main/Entry file
52
+ app.use(VsUpload.plugin);
53
+ ```
54
+
55
+ ```html
56
+ <template>
57
+ <vs-upload v-model="files" />
58
+ </template>
59
+ ```
60
+
61
+ <br />
62
+
63
+ ## Props
64
+
65
+ | Name | Type | Default | Options | Description |
66
+ | ---------- | ------- | ------- | ----------------------------- | ------------------------------------------- |
67
+ | modelValue | Array | `[]` | — | v-model binding; array of `File` objects |
68
+ | label | String | — | — | Label displayed above the dropzone |
69
+ | hint | String | — | — | Hint text displayed below the label |
70
+ | accept | String | — | Any valid MIME type or ext | Restricts the accepted file types |
71
+ | multiple | Boolean | `false` | — | Allows selecting multiple files |
72
+ | disabled | Boolean | `false` | — | Disables the component |
73
+ | validation | String | — | `success`, `warning`, `error` | Applies a validation state to the dropzone |
74
+ | message | String | — | — | Validation message shown below the dropzone |
75
+
76
+ <br />
77
+
78
+ ## Emits
79
+
80
+ | Event | Payload | Description |
81
+ | ------------------- | -------- | ------------------------------------------------- |
82
+ | `update:modelValue` | `File[]` | Emitted when files are added or removed (v-model) |
83
+ | `change` | `File[]` | Emitted when the file list changes |
84
+ | `reject` | — | Reserved for future file-rejection callbacks |
85
+
86
+ <br />
87
+
88
+ ## CSS Variables
89
+
90
+ | Variable | Default | Description |
91
+ | -------------------------------------- | --------- | ------------------------------- |
92
+ | `--vs-upload-label-color` | `#2f3941` | Label text color |
93
+ | `--vs-upload-hint-color` | `#68737d` | Hint text color |
94
+ | `--vs-upload-dropzone-border` | `#d8dcde` | Dropzone border color |
95
+ | `--vs-upload-dropzone-bg` | `#ffffff` | Dropzone background |
96
+ | `--vs-upload-dropzone-color` | `#1f73b7` | Dropzone icon and text color |
97
+ | `--vs-upload-dropzone-border-dragging` | `#1f73b7` | Border color when dragging over |
98
+ | `--vs-upload-dropzone-bg-dragging` | `#eaf4ff` | Background when dragging over |
99
+ | `--vs-upload-file-border` | `#e9ebed` | File item border color |
100
+ | `--vs-upload-file-bg` | `#ffffff` | File item background |
101
+ | `--vs-upload-file-color` | `#2f3941` | File item text color |
102
+ | `--vs-upload-file-size-color` | `#87929d` | File size text color |
103
+ | `--vs-upload-remove-color` | `#cc3340` | Remove button color |
104
+ | `--vs-upload-remove-hover-color` | `#8c232c` | Remove button hover color |
@@ -0,0 +1,31 @@
1
+ import vue from '@vitejs/plugin-vue';
2
+ import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
3
+
4
+ export default {
5
+ plugins: [vue(), cssInjectedByJsPlugin()],
6
+ build: {
7
+ cssCodeSplit: true,
8
+ lib: {
9
+ entry: './src/index.js',
10
+ formats: ['es', 'umd', 'iife'],
11
+ name: 'VsUpload',
12
+ fileName: format => {
13
+ if (format === 'es') {
14
+ return 'index.esm.js';
15
+ }
16
+ if (format === 'umd') {
17
+ return 'index.umd.js';
18
+ }
19
+ return 'index.min.js';
20
+ },
21
+ },
22
+ rollupOptions: {
23
+ external: ['vue'],
24
+ output: {
25
+ globals: {
26
+ vue: 'Vue',
27
+ },
28
+ },
29
+ },
30
+ },
31
+ };
@@ -0,0 +1,203 @@
1
+ (function(){"use strict";try{if(typeof document<"u"){var o=document.createElement("style");o.appendChild(document.createTextNode("[data-theme=dark] .vs-upload,.dark .vs-upload{--vs-upload-label-color: #b0b8c1;--vs-upload-hint-color: #8090a2;--vs-upload-dropzone-border: #3a4553;--vs-upload-dropzone-bg: #1a1f26;--vs-upload-dropzone-color: #4b9fea;--vs-upload-dropzone-border-dragging: #42a5f5;--vs-upload-dropzone-bg-dragging: #1a2535;--vs-upload-file-border: #2a3038;--vs-upload-file-bg: #1a1f26;--vs-upload-file-color: #b0b8c1;--vs-upload-file-size-color: #5a6472;--vs-upload-remove-color: #e05252;--vs-upload-remove-hover-color: #cc3340}.vs-upload{--vs-upload-label-color: #2f3941;--vs-upload-hint-color: #68737d;--vs-upload-dropzone-border: #d8dcde;--vs-upload-dropzone-bg: #ffffff;--vs-upload-dropzone-color: #1f73b7;--vs-upload-dropzone-border-dragging: #1f73b7;--vs-upload-dropzone-bg-dragging: #eaf4ff;--vs-upload-file-border: #e9ebed;--vs-upload-file-bg: #ffffff;--vs-upload-file-color: #2f3941;--vs-upload-file-size-color: #87929d;--vs-upload-remove-color: #cc3340;--vs-upload-remove-hover-color: #8c232c;--vs-upload-error-color: #cc3340;--vs-upload-warning-color: #ad5918;--vs-upload-success-color: #186146;--vs-upload-border-radius: 4px;display:flex;flex-direction:column;font-family:inherit}.vs-upload__label{display:inline-block;margin-bottom:8px;font-size:14px;font-weight:600;color:var(--vs-upload-label-color);line-height:1.4;cursor:default}.vs-upload__hint{margin:-8px 0 8px;font-size:13px;color:var(--vs-upload-hint-color);line-height:1.4}.vs-upload__dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:28px 20px;border:2px dashed var(--vs-upload-dropzone-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-dropzone-bg);color:var(--vs-upload-dropzone-color);cursor:pointer;transition:border-color .2s ease,background .2s ease}.vs-upload__dropzone:hover,.vs-upload__dropzone--dragging{border-color:var(--vs-upload-dropzone-border-dragging);background:var(--vs-upload-dropzone-bg-dragging)}.vs-upload__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.vs-upload__dropzone-icon{flex-shrink:0}.vs-upload__dropzone-text{font-size:14px;font-weight:500;text-align:center;line-height:1.4}.vs-upload__file-list{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}.vs-upload__file-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--vs-upload-file-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-file-bg);color:var(--vs-upload-file-color)}.vs-upload__file-icon{flex-shrink:0;color:var(--vs-upload-hint-color)}.vs-upload__file-name{flex:1;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vs-upload__file-size{font-size:12px;color:var(--vs-upload-file-size-color);flex-shrink:0}.vs-upload__remove{display:flex;align-items:center;margin-left:4px;background:none;border:none;cursor:pointer;color:var(--vs-upload-remove-color);border-radius:2px;transition:color .15s ease}.vs-upload__remove:hover:not(:disabled){color:var(--vs-upload-remove-hover-color)}.vs-upload__remove:disabled{opacity:.4;cursor:not-allowed}.vs-upload__message{margin:6px 0 0;font-size:12px;line-height:1.4;color:var(--vs-upload-hint-color)}.vs-upload__message--error{color:var(--vs-upload-error-color)}.vs-upload__message--warning{color:var(--vs-upload-warning-color)}.vs-upload__message--success{color:var(--vs-upload-success-color)}.vs-upload--error .vs-upload__dropzone{border-color:var(--vs-upload-error-color)}.vs-upload--warning .vs-upload__dropzone{border-color:var(--vs-upload-warning-color)}.vs-upload--success .vs-upload__dropzone{border-color:var(--vs-upload-success-color)}.vs-upload--compact .vs-upload__dropzone{padding:14px 16px;flex-direction:row;gap:8px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-icon{width:16px;height:16px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-text{font-size:13px}.vs-upload--compact .vs-upload__file-item{padding:6px 10px}.vs-upload--compact .vs-upload__file-name{font-size:13px}.vs-upload--disabled .vs-upload__dropzone{opacity:.6;cursor:not-allowed}.vs-upload--disabled .vs-upload__dropzone:hover{border-color:var(--vs-upload-dropzone-border);background:var(--vs-upload-dropzone-bg)}")),document.head.appendChild(o)}}catch(r){console.error("vite-plugin-css-injected-by-js",r)}})();
2
+ import { openBlock as a, createElementBlock as o, normalizeClass as c, toDisplayString as d, createCommentVNode as p, createElementVNode as r, withModifiers as u, createStaticVNode as v, Fragment as m, renderList as y } from "vue";
3
+ const f = (t, e) => {
4
+ const i = t.__vccOpts || t;
5
+ for (const [g, n] of e)
6
+ i[g] = n;
7
+ return i;
8
+ };
9
+ let _ = 0;
10
+ const x = {
11
+ name: "VsUpload",
12
+ inheritAttrs: !1,
13
+ props: {
14
+ modelValue: {
15
+ type: Array,
16
+ default: () => []
17
+ },
18
+ label: {
19
+ type: String
20
+ },
21
+ hint: {
22
+ type: String
23
+ },
24
+ accept: {
25
+ type: String
26
+ },
27
+ multiple: {
28
+ type: Boolean,
29
+ default: !1
30
+ },
31
+ disabled: {
32
+ type: Boolean,
33
+ default: !1
34
+ },
35
+ isCompact: {
36
+ type: Boolean,
37
+ default: !1
38
+ },
39
+ validation: {
40
+ type: String,
41
+ validator: (t) => ["success", "warning", "error"].includes(t)
42
+ },
43
+ message: {
44
+ type: String
45
+ }
46
+ },
47
+ emits: ["update:modelValue", "change", "reject"],
48
+ data() {
49
+ return {
50
+ inputId: `vs-upload-${++_}`,
51
+ isDragging: !1
52
+ };
53
+ },
54
+ computed: {
55
+ containerClass() {
56
+ return {
57
+ "vs-upload--disabled": this.disabled,
58
+ "vs-upload--compact": this.isCompact,
59
+ [`vs-upload--${this.validation}`]: !!this.validation
60
+ };
61
+ },
62
+ ariaDescribedBy() {
63
+ const t = [];
64
+ return this.hint && t.push(`${this.inputId}-hint`), this.message && t.push(`${this.inputId}-message`), t.length ? t.join(" ") : void 0;
65
+ }
66
+ },
67
+ methods: {
68
+ openFilePicker() {
69
+ this.disabled || this.$refs.fileInput.click();
70
+ },
71
+ onDragOver() {
72
+ this.disabled || (this.isDragging = !0);
73
+ },
74
+ onDragLeave() {
75
+ this.isDragging = !1;
76
+ },
77
+ onDrop(t) {
78
+ this.isDragging = !1, !this.disabled && this.addFiles(t.dataTransfer.files);
79
+ },
80
+ onFileInput(t) {
81
+ this.addFiles(t.target.files), t.target.value = "";
82
+ },
83
+ addFiles(t) {
84
+ if (!t || !t.length)
85
+ return;
86
+ const e = Array.from(t), i = this.multiple ? [...this.modelValue || [], ...e] : [e[0]];
87
+ this.$emit("update:modelValue", i), this.$emit("change", i);
88
+ },
89
+ removeFile(t) {
90
+ const e = [...this.modelValue || []];
91
+ e.splice(t, 1), this.$emit("update:modelValue", e), this.$emit("change", e);
92
+ },
93
+ getFileIconSvg(t) {
94
+ const e = (t.split(".").pop() || "").toLowerCase(), i = 'xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"';
95
+ return ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico"].includes(e) ? `<svg ${i}><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>` : ["mp4", "mov", "avi", "mkv", "webm"].includes(e) ? `<svg ${i}><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>` : ["mp3", "wav", "ogg", "flac", "aac"].includes(e) ? `<svg ${i}><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>` : e === "pdf" ? `<svg ${i}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>` : ["zip", "rar", "tar", "gz", "7z"].includes(e) ? '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" focusable="false" viewBox="0 0 16 16" aria-hidden="true" data-garden-id="forms.file.icon" data-garden-version="9.12.6" class="StyledBaseIcon-sc-1moykgb-0 StyledFileIcon-sc-7b3q0c-0 eWlVPJ goYdHe"><path fill="none" stroke="currentColor" stroke-linecap="round" d="M6.5.5v11M5 2.5h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m8-6.3V15c0 .28-.22.5-.5.5H2c-.28 0-.5-.22-.5-.5V1c0-.28.22-.5.5-.5h8.85c.13 0 .26.05.36.15l3.15 3.2c.09.1.14.22.14.35zm-4-3.7V4c0 .28.22.5.5.5h3.5"></path></svg>' : ["xls", "xlsx", "csv"].includes(e) ? `<svg ${i}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/><line x1="8" y1="9" x2="10" y2="9"/></svg>` : ["ppt", "pptx"].includes(e) ? `<svg ${i}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M8 13h5a2 2 0 0 0 0-4H8v8"/></svg>` : [
96
+ "js",
97
+ "ts",
98
+ "jsx",
99
+ "tsx",
100
+ "html",
101
+ "css",
102
+ "scss",
103
+ "json",
104
+ "xml",
105
+ "py",
106
+ "rb",
107
+ "go",
108
+ "java",
109
+ "php",
110
+ "c",
111
+ "cpp",
112
+ "cs",
113
+ "sh",
114
+ "yml",
115
+ "yaml",
116
+ "md"
117
+ ].includes(e) ? `<svg ${i}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>` : ["txt", "doc", "docx", "rtf"].includes(e) ? `<svg ${i}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>` : `<svg ${i}><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>`;
118
+ },
119
+ formatSize(t) {
120
+ return t === 0 ? "0 B" : t < 1024 ? `${t} B` : t < 1024 * 1024 ? `${(t / 1024).toFixed(1)} KB` : `${(t / (1024 * 1024)).toFixed(1)} MB`;
121
+ }
122
+ }
123
+ }, w = ["for"], k = ["id"], b = ["id", "accept", "multiple", "disabled", "aria-describedby"], V = {
124
+ key: 2,
125
+ class: "vs-upload__file-list",
126
+ role: "list"
127
+ }, D = ["innerHTML"], z = ["title"], M = { class: "vs-upload__file-size" }, C = ["aria-label", "disabled", "onClick"], F = ["id"];
128
+ function B(t, e, i, g, n, l) {
129
+ return a(), o("div", {
130
+ class: c(["vs-upload", l.containerClass])
131
+ }, [
132
+ i.label ? (a(), o("label", {
133
+ key: 0,
134
+ for: n.inputId,
135
+ class: "vs-upload__label"
136
+ }, d(i.label), 9, w)) : p("", !0),
137
+ i.hint ? (a(), o("span", {
138
+ key: 1,
139
+ class: "vs-upload__hint",
140
+ id: `${n.inputId}-hint`
141
+ }, d(i.hint), 9, k)) : p("", !0),
142
+ r("div", {
143
+ class: c(["vs-upload__dropzone", { "vs-upload__dropzone--dragging": n.isDragging }]),
144
+ onDragover: e[1] || (e[1] = u((...s) => l.onDragOver && l.onDragOver(...s), ["prevent"])),
145
+ onDragleave: e[2] || (e[2] = u((...s) => l.onDragLeave && l.onDragLeave(...s), ["prevent"])),
146
+ onDrop: e[3] || (e[3] = u((...s) => l.onDrop && l.onDrop(...s), ["prevent"])),
147
+ onClick: e[4] || (e[4] = (...s) => l.openFilePicker && l.openFilePicker(...s))
148
+ }, [
149
+ r("input", {
150
+ id: n.inputId,
151
+ ref: "fileInput",
152
+ type: "file",
153
+ class: "vs-upload__input",
154
+ accept: i.accept,
155
+ multiple: i.multiple,
156
+ disabled: i.disabled,
157
+ "aria-describedby": l.ariaDescribedBy,
158
+ onChange: e[0] || (e[0] = (...s) => l.onFileInput && l.onFileInput(...s))
159
+ }, null, 40, b),
160
+ e[5] || (e[5] = v('<svg class="vs-upload__dropzone-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg><span class="vs-upload__dropzone-text">Choose a file or drag and drop here</span>', 2))
161
+ ], 34),
162
+ i.modelValue && i.modelValue.length ? (a(), o("ul", V, [
163
+ (a(!0), o(m, null, y(i.modelValue, (s, h) => (a(), o("li", {
164
+ key: `${s.name}-${h}`,
165
+ class: "vs-upload__file-item"
166
+ }, [
167
+ r("span", {
168
+ class: "vs-upload__file-icon",
169
+ "aria-hidden": "true",
170
+ innerHTML: l.getFileIconSvg(s.name)
171
+ }, null, 8, D),
172
+ r("span", {
173
+ class: "vs-upload__file-name",
174
+ title: s.name
175
+ }, d(s.name), 9, z),
176
+ r("span", M, d(l.formatSize(s.size)), 1),
177
+ r("button", {
178
+ type: "button",
179
+ class: "vs-upload__remove",
180
+ "aria-label": `Remove ${s.name}`,
181
+ disabled: i.disabled,
182
+ onClick: u((I) => l.removeFile(h), ["stop"])
183
+ }, [...e[6] || (e[6] = [
184
+ v('<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"></path><path d="M10 11v6"></path><path d="M14 11v6"></path><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"></path></svg>', 1)
185
+ ])], 8, C)
186
+ ]))), 128))
187
+ ])) : p("", !0),
188
+ i.message ? (a(), o("span", {
189
+ key: 3,
190
+ class: c(["vs-upload__message", `vs-upload__message--${i.validation}`]),
191
+ id: `${n.inputId}-message`
192
+ }, d(i.message), 11, F)) : p("", !0)
193
+ ], 2);
194
+ }
195
+ const H = /* @__PURE__ */ f(x, [["render", B]]), j = {
196
+ install(t) {
197
+ t.component("VsUpload", H);
198
+ }
199
+ };
200
+ export {
201
+ H as default,
202
+ j as plugin
203
+ };
@@ -0,0 +1,3 @@
1
+ (function(){"use strict";try{if(typeof document<"u"){var o=document.createElement("style");o.appendChild(document.createTextNode("[data-theme=dark] .vs-upload,.dark .vs-upload{--vs-upload-label-color: #b0b8c1;--vs-upload-hint-color: #8090a2;--vs-upload-dropzone-border: #3a4553;--vs-upload-dropzone-bg: #1a1f26;--vs-upload-dropzone-color: #4b9fea;--vs-upload-dropzone-border-dragging: #42a5f5;--vs-upload-dropzone-bg-dragging: #1a2535;--vs-upload-file-border: #2a3038;--vs-upload-file-bg: #1a1f26;--vs-upload-file-color: #b0b8c1;--vs-upload-file-size-color: #5a6472;--vs-upload-remove-color: #e05252;--vs-upload-remove-hover-color: #cc3340}.vs-upload{--vs-upload-label-color: #2f3941;--vs-upload-hint-color: #68737d;--vs-upload-dropzone-border: #d8dcde;--vs-upload-dropzone-bg: #ffffff;--vs-upload-dropzone-color: #1f73b7;--vs-upload-dropzone-border-dragging: #1f73b7;--vs-upload-dropzone-bg-dragging: #eaf4ff;--vs-upload-file-border: #e9ebed;--vs-upload-file-bg: #ffffff;--vs-upload-file-color: #2f3941;--vs-upload-file-size-color: #87929d;--vs-upload-remove-color: #cc3340;--vs-upload-remove-hover-color: #8c232c;--vs-upload-error-color: #cc3340;--vs-upload-warning-color: #ad5918;--vs-upload-success-color: #186146;--vs-upload-border-radius: 4px;display:flex;flex-direction:column;font-family:inherit}.vs-upload__label{display:inline-block;margin-bottom:8px;font-size:14px;font-weight:600;color:var(--vs-upload-label-color);line-height:1.4;cursor:default}.vs-upload__hint{margin:-8px 0 8px;font-size:13px;color:var(--vs-upload-hint-color);line-height:1.4}.vs-upload__dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:28px 20px;border:2px dashed var(--vs-upload-dropzone-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-dropzone-bg);color:var(--vs-upload-dropzone-color);cursor:pointer;transition:border-color .2s ease,background .2s ease}.vs-upload__dropzone:hover,.vs-upload__dropzone--dragging{border-color:var(--vs-upload-dropzone-border-dragging);background:var(--vs-upload-dropzone-bg-dragging)}.vs-upload__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.vs-upload__dropzone-icon{flex-shrink:0}.vs-upload__dropzone-text{font-size:14px;font-weight:500;text-align:center;line-height:1.4}.vs-upload__file-list{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}.vs-upload__file-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--vs-upload-file-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-file-bg);color:var(--vs-upload-file-color)}.vs-upload__file-icon{flex-shrink:0;color:var(--vs-upload-hint-color)}.vs-upload__file-name{flex:1;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vs-upload__file-size{font-size:12px;color:var(--vs-upload-file-size-color);flex-shrink:0}.vs-upload__remove{display:flex;align-items:center;margin-left:4px;background:none;border:none;cursor:pointer;color:var(--vs-upload-remove-color);border-radius:2px;transition:color .15s ease}.vs-upload__remove:hover:not(:disabled){color:var(--vs-upload-remove-hover-color)}.vs-upload__remove:disabled{opacity:.4;cursor:not-allowed}.vs-upload__message{margin:6px 0 0;font-size:12px;line-height:1.4;color:var(--vs-upload-hint-color)}.vs-upload__message--error{color:var(--vs-upload-error-color)}.vs-upload__message--warning{color:var(--vs-upload-warning-color)}.vs-upload__message--success{color:var(--vs-upload-success-color)}.vs-upload--error .vs-upload__dropzone{border-color:var(--vs-upload-error-color)}.vs-upload--warning .vs-upload__dropzone{border-color:var(--vs-upload-warning-color)}.vs-upload--success .vs-upload__dropzone{border-color:var(--vs-upload-success-color)}.vs-upload--compact .vs-upload__dropzone{padding:14px 16px;flex-direction:row;gap:8px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-icon{width:16px;height:16px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-text{font-size:13px}.vs-upload--compact .vs-upload__file-item{padding:6px 10px}.vs-upload--compact .vs-upload__file-name{font-size:13px}.vs-upload--disabled .vs-upload__dropzone{opacity:.6;cursor:not-allowed}.vs-upload--disabled .vs-upload__dropzone:hover{border-color:var(--vs-upload-dropzone-border);background:var(--vs-upload-dropzone-bg)}")),document.head.appendChild(o)}}catch(r){console.error("vite-plugin-css-injected-by-js",r)}})();
2
+ var VsUpload=function(t,e){"use strict";var d=document.createElement("style");d.textContent=`[data-theme=dark] .vs-upload,.dark .vs-upload{--vs-upload-label-color: #b0b8c1;--vs-upload-hint-color: #8090a2;--vs-upload-dropzone-border: #3a4553;--vs-upload-dropzone-bg: #1a1f26;--vs-upload-dropzone-color: #4b9fea;--vs-upload-dropzone-border-dragging: #42a5f5;--vs-upload-dropzone-bg-dragging: #1a2535;--vs-upload-file-border: #2a3038;--vs-upload-file-bg: #1a1f26;--vs-upload-file-color: #b0b8c1;--vs-upload-file-size-color: #5a6472;--vs-upload-remove-color: #e05252;--vs-upload-remove-hover-color: #cc3340}.vs-upload{--vs-upload-label-color: #2f3941;--vs-upload-hint-color: #68737d;--vs-upload-dropzone-border: #d8dcde;--vs-upload-dropzone-bg: #ffffff;--vs-upload-dropzone-color: #1f73b7;--vs-upload-dropzone-border-dragging: #1f73b7;--vs-upload-dropzone-bg-dragging: #eaf4ff;--vs-upload-file-border: #e9ebed;--vs-upload-file-bg: #ffffff;--vs-upload-file-color: #2f3941;--vs-upload-file-size-color: #87929d;--vs-upload-remove-color: #cc3340;--vs-upload-remove-hover-color: #8c232c;--vs-upload-error-color: #cc3340;--vs-upload-warning-color: #ad5918;--vs-upload-success-color: #186146;--vs-upload-border-radius: 4px;display:flex;flex-direction:column;font-family:inherit}.vs-upload__label{display:inline-block;margin-bottom:8px;font-size:14px;font-weight:600;color:var(--vs-upload-label-color);line-height:1.4;cursor:default}.vs-upload__hint{margin:-8px 0 8px;font-size:13px;color:var(--vs-upload-hint-color);line-height:1.4}.vs-upload__dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:28px 20px;border:2px dashed var(--vs-upload-dropzone-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-dropzone-bg);color:var(--vs-upload-dropzone-color);cursor:pointer;transition:border-color .2s ease,background .2s ease}.vs-upload__dropzone:hover,.vs-upload__dropzone--dragging{border-color:var(--vs-upload-dropzone-border-dragging);background:var(--vs-upload-dropzone-bg-dragging)}.vs-upload__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.vs-upload__dropzone-icon{flex-shrink:0}.vs-upload__dropzone-text{font-size:14px;font-weight:500;text-align:center;line-height:1.4}.vs-upload__file-list{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}.vs-upload__file-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--vs-upload-file-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-file-bg);color:var(--vs-upload-file-color)}.vs-upload__file-icon{flex-shrink:0;color:var(--vs-upload-hint-color)}.vs-upload__file-name{flex:1;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vs-upload__file-size{font-size:12px;color:var(--vs-upload-file-size-color);flex-shrink:0}.vs-upload__remove{display:flex;align-items:center;margin-left:4px;background:none;border:none;cursor:pointer;color:var(--vs-upload-remove-color);border-radius:2px;transition:color .15s ease}.vs-upload__remove:hover:not(:disabled){color:var(--vs-upload-remove-hover-color)}.vs-upload__remove:disabled{opacity:.4;cursor:not-allowed}.vs-upload__message{margin:6px 0 0;font-size:12px;line-height:1.4;color:var(--vs-upload-hint-color)}.vs-upload__message--error{color:var(--vs-upload-error-color)}.vs-upload__message--warning{color:var(--vs-upload-warning-color)}.vs-upload__message--success{color:var(--vs-upload-success-color)}.vs-upload--error .vs-upload__dropzone{border-color:var(--vs-upload-error-color)}.vs-upload--warning .vs-upload__dropzone{border-color:var(--vs-upload-warning-color)}.vs-upload--success .vs-upload__dropzone{border-color:var(--vs-upload-success-color)}.vs-upload--compact .vs-upload__dropzone{padding:14px 16px;flex-direction:row;gap:8px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-icon{width:16px;height:16px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-text{font-size:13px}.vs-upload--compact .vs-upload__file-item{padding:6px 10px}.vs-upload--compact .vs-upload__file-name{font-size:13px}.vs-upload--disabled .vs-upload__dropzone{opacity:.6;cursor:not-allowed}.vs-upload--disabled .vs-upload__dropzone:hover{border-color:var(--vs-upload-dropzone-border);background:var(--vs-upload-dropzone-bg)}
3
+ `,document.head.appendChild(d);const B="",u=(l,o)=>{const a=l.__vccOpts||l;for(const[p,i]of o)a[p]=i;return a};let v=0;const g={name:"VsUpload",inheritAttrs:!1,props:{modelValue:{type:Array,default:()=>[]},label:{type:String},hint:{type:String},accept:{type:String},multiple:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},isCompact:{type:Boolean,default:!1},validation:{type:String,validator:l=>["success","warning","error"].includes(l)},message:{type:String}},emits:["update:modelValue","change","reject"],data(){return{inputId:`vs-upload-${++v}`,isDragging:!1}},computed:{containerClass(){return{"vs-upload--disabled":this.disabled,"vs-upload--compact":this.isCompact,[`vs-upload--${this.validation}`]:!!this.validation}},ariaDescribedBy(){const l=[];return this.hint&&l.push(`${this.inputId}-hint`),this.message&&l.push(`${this.inputId}-message`),l.length?l.join(" "):void 0}},methods:{openFilePicker(){this.disabled||this.$refs.fileInput.click()},onDragOver(){this.disabled||(this.isDragging=!0)},onDragLeave(){this.isDragging=!1},onDrop(l){this.isDragging=!1,!this.disabled&&this.addFiles(l.dataTransfer.files)},onFileInput(l){this.addFiles(l.target.files),l.target.value=""},addFiles(l){if(!l||!l.length)return;const o=Array.from(l),a=this.multiple?[...this.modelValue||[],...o]:[o[0]];this.$emit("update:modelValue",a),this.$emit("change",a)},removeFile(l){const o=[...this.modelValue||[]];o.splice(l,1),this.$emit("update:modelValue",o),this.$emit("change",o)},getFileIconSvg(l){const o=(l.split(".").pop()||"").toLowerCase(),a='xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"';return["jpg","jpeg","png","gif","webp","svg","bmp","ico"].includes(o)?`<svg ${a}><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`:["mp4","mov","avi","mkv","webm"].includes(o)?`<svg ${a}><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`:["mp3","wav","ogg","flac","aac"].includes(o)?`<svg ${a}><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>`:o==="pdf"?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>`:["zip","rar","tar","gz","7z"].includes(o)?'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" focusable="false" viewBox="0 0 16 16" aria-hidden="true" data-garden-id="forms.file.icon" data-garden-version="9.12.6" class="StyledBaseIcon-sc-1moykgb-0 StyledFileIcon-sc-7b3q0c-0 eWlVPJ goYdHe"><path fill="none" stroke="currentColor" stroke-linecap="round" d="M6.5.5v11M5 2.5h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m8-6.3V15c0 .28-.22.5-.5.5H2c-.28 0-.5-.22-.5-.5V1c0-.28.22-.5.5-.5h8.85c.13 0 .26.05.36.15l3.15 3.2c.09.1.14.22.14.35zm-4-3.7V4c0 .28.22.5.5.5h3.5"></path></svg>':["xls","xlsx","csv"].includes(o)?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/><line x1="8" y1="9" x2="10" y2="9"/></svg>`:["ppt","pptx"].includes(o)?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M8 13h5a2 2 0 0 0 0-4H8v8"/></svg>`:["js","ts","jsx","tsx","html","css","scss","json","xml","py","rb","go","java","php","c","cpp","cs","sh","yml","yaml","md"].includes(o)?`<svg ${a}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>`:["txt","doc","docx","rtf"].includes(o)?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>`:`<svg ${a}><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>`},formatSize(l){return l===0?"0 B":l<1024?`${l} B`:l<1024*1024?`${(l/1024).toFixed(1)} KB`:`${(l/(1024*1024)).toFixed(1)} MB`}}},h=["for"],m=["id"],f=["id","accept","multiple","disabled","aria-describedby"],_={key:2,class:"vs-upload__file-list",role:"list"},x=["innerHTML"],b=["title"],y={class:"vs-upload__file-size"},z=["aria-label","disabled","onClick"],k=["id"];function w(l,o,a,p,i,s){return e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["vs-upload",s.containerClass])},[a.label?(e.openBlock(),e.createElementBlock("label",{key:0,for:i.inputId,class:"vs-upload__label"},e.toDisplayString(a.label),9,h)):e.createCommentVNode("",!0),a.hint?(e.openBlock(),e.createElementBlock("span",{key:1,class:"vs-upload__hint",id:`${i.inputId}-hint`},e.toDisplayString(a.hint),9,m)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:e.normalizeClass(["vs-upload__dropzone",{"vs-upload__dropzone--dragging":i.isDragging}]),onDragover:o[1]||(o[1]=e.withModifiers((...r)=>s.onDragOver&&s.onDragOver(...r),["prevent"])),onDragleave:o[2]||(o[2]=e.withModifiers((...r)=>s.onDragLeave&&s.onDragLeave(...r),["prevent"])),onDrop:o[3]||(o[3]=e.withModifiers((...r)=>s.onDrop&&s.onDrop(...r),["prevent"])),onClick:o[4]||(o[4]=(...r)=>s.openFilePicker&&s.openFilePicker(...r))},[e.createElementVNode("input",{id:i.inputId,ref:"fileInput",type:"file",class:"vs-upload__input",accept:a.accept,multiple:a.multiple,disabled:a.disabled,"aria-describedby":s.ariaDescribedBy,onChange:o[0]||(o[0]=(...r)=>s.onFileInput&&s.onFileInput(...r))},null,40,f),o[5]||(o[5]=e.createStaticVNode('<svg class="vs-upload__dropzone-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg><span class="vs-upload__dropzone-text">Choose a file or drag and drop here</span>',2))],34),a.modelValue&&a.modelValue.length?(e.openBlock(),e.createElementBlock("ul",_,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.modelValue,(r,c)=>(e.openBlock(),e.createElementBlock("li",{key:`${r.name}-${c}`,class:"vs-upload__file-item"},[e.createElementVNode("span",{class:"vs-upload__file-icon","aria-hidden":"true",innerHTML:s.getFileIconSvg(r.name)},null,8,x),e.createElementVNode("span",{class:"vs-upload__file-name",title:r.name},e.toDisplayString(r.name),9,b),e.createElementVNode("span",y,e.toDisplayString(s.formatSize(r.size)),1),e.createElementVNode("button",{type:"button",class:"vs-upload__remove","aria-label":`Remove ${r.name}`,disabled:a.disabled,onClick:e.withModifiers(C=>s.removeFile(c),["stop"])},[...o[6]||(o[6]=[e.createStaticVNode('<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"></path><path d="M10 11v6"></path><path d="M14 11v6"></path><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"></path></svg>',1)])],8,z)]))),128))])):e.createCommentVNode("",!0),a.message?(e.openBlock(),e.createElementBlock("span",{key:3,class:e.normalizeClass(["vs-upload__message",`vs-upload__message--${a.validation}`]),id:`${i.inputId}-message`},e.toDisplayString(a.message),11,k)):e.createCommentVNode("",!0)],2)}const n=u(g,[["render",w]]),V={install(l){l.component("VsUpload",n)}};return t.default=n,t.plugin=V,Object.defineProperties(t,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),t}({},Vue);
@@ -0,0 +1,3 @@
1
+ (function(){"use strict";try{if(typeof document<"u"){var o=document.createElement("style");o.appendChild(document.createTextNode("[data-theme=dark] .vs-upload,.dark .vs-upload{--vs-upload-label-color: #b0b8c1;--vs-upload-hint-color: #8090a2;--vs-upload-dropzone-border: #3a4553;--vs-upload-dropzone-bg: #1a1f26;--vs-upload-dropzone-color: #4b9fea;--vs-upload-dropzone-border-dragging: #42a5f5;--vs-upload-dropzone-bg-dragging: #1a2535;--vs-upload-file-border: #2a3038;--vs-upload-file-bg: #1a1f26;--vs-upload-file-color: #b0b8c1;--vs-upload-file-size-color: #5a6472;--vs-upload-remove-color: #e05252;--vs-upload-remove-hover-color: #cc3340}.vs-upload{--vs-upload-label-color: #2f3941;--vs-upload-hint-color: #68737d;--vs-upload-dropzone-border: #d8dcde;--vs-upload-dropzone-bg: #ffffff;--vs-upload-dropzone-color: #1f73b7;--vs-upload-dropzone-border-dragging: #1f73b7;--vs-upload-dropzone-bg-dragging: #eaf4ff;--vs-upload-file-border: #e9ebed;--vs-upload-file-bg: #ffffff;--vs-upload-file-color: #2f3941;--vs-upload-file-size-color: #87929d;--vs-upload-remove-color: #cc3340;--vs-upload-remove-hover-color: #8c232c;--vs-upload-error-color: #cc3340;--vs-upload-warning-color: #ad5918;--vs-upload-success-color: #186146;--vs-upload-border-radius: 4px;display:flex;flex-direction:column;font-family:inherit}.vs-upload__label{display:inline-block;margin-bottom:8px;font-size:14px;font-weight:600;color:var(--vs-upload-label-color);line-height:1.4;cursor:default}.vs-upload__hint{margin:-8px 0 8px;font-size:13px;color:var(--vs-upload-hint-color);line-height:1.4}.vs-upload__dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:28px 20px;border:2px dashed var(--vs-upload-dropzone-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-dropzone-bg);color:var(--vs-upload-dropzone-color);cursor:pointer;transition:border-color .2s ease,background .2s ease}.vs-upload__dropzone:hover,.vs-upload__dropzone--dragging{border-color:var(--vs-upload-dropzone-border-dragging);background:var(--vs-upload-dropzone-bg-dragging)}.vs-upload__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.vs-upload__dropzone-icon{flex-shrink:0}.vs-upload__dropzone-text{font-size:14px;font-weight:500;text-align:center;line-height:1.4}.vs-upload__file-list{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}.vs-upload__file-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--vs-upload-file-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-file-bg);color:var(--vs-upload-file-color)}.vs-upload__file-icon{flex-shrink:0;color:var(--vs-upload-hint-color)}.vs-upload__file-name{flex:1;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vs-upload__file-size{font-size:12px;color:var(--vs-upload-file-size-color);flex-shrink:0}.vs-upload__remove{display:flex;align-items:center;margin-left:4px;background:none;border:none;cursor:pointer;color:var(--vs-upload-remove-color);border-radius:2px;transition:color .15s ease}.vs-upload__remove:hover:not(:disabled){color:var(--vs-upload-remove-hover-color)}.vs-upload__remove:disabled{opacity:.4;cursor:not-allowed}.vs-upload__message{margin:6px 0 0;font-size:12px;line-height:1.4;color:var(--vs-upload-hint-color)}.vs-upload__message--error{color:var(--vs-upload-error-color)}.vs-upload__message--warning{color:var(--vs-upload-warning-color)}.vs-upload__message--success{color:var(--vs-upload-success-color)}.vs-upload--error .vs-upload__dropzone{border-color:var(--vs-upload-error-color)}.vs-upload--warning .vs-upload__dropzone{border-color:var(--vs-upload-warning-color)}.vs-upload--success .vs-upload__dropzone{border-color:var(--vs-upload-success-color)}.vs-upload--compact .vs-upload__dropzone{padding:14px 16px;flex-direction:row;gap:8px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-icon{width:16px;height:16px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-text{font-size:13px}.vs-upload--compact .vs-upload__file-item{padding:6px 10px}.vs-upload--compact .vs-upload__file-name{font-size:13px}.vs-upload--disabled .vs-upload__dropzone{opacity:.6;cursor:not-allowed}.vs-upload--disabled .vs-upload__dropzone:hover{border-color:var(--vs-upload-dropzone-border);background:var(--vs-upload-dropzone-bg)}")),document.head.appendChild(o)}}catch(r){console.error("vite-plugin-css-injected-by-js",r)}})();
2
+ (function(i,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(i=typeof globalThis<"u"?globalThis:i||self,e(i.VsUpload={},i.Vue))})(this,function(i,e){"use strict";var t=document.createElement("style");t.textContent=`[data-theme=dark] .vs-upload,.dark .vs-upload{--vs-upload-label-color: #b0b8c1;--vs-upload-hint-color: #8090a2;--vs-upload-dropzone-border: #3a4553;--vs-upload-dropzone-bg: #1a1f26;--vs-upload-dropzone-color: #4b9fea;--vs-upload-dropzone-border-dragging: #42a5f5;--vs-upload-dropzone-bg-dragging: #1a2535;--vs-upload-file-border: #2a3038;--vs-upload-file-bg: #1a1f26;--vs-upload-file-color: #b0b8c1;--vs-upload-file-size-color: #5a6472;--vs-upload-remove-color: #e05252;--vs-upload-remove-hover-color: #cc3340}.vs-upload{--vs-upload-label-color: #2f3941;--vs-upload-hint-color: #68737d;--vs-upload-dropzone-border: #d8dcde;--vs-upload-dropzone-bg: #ffffff;--vs-upload-dropzone-color: #1f73b7;--vs-upload-dropzone-border-dragging: #1f73b7;--vs-upload-dropzone-bg-dragging: #eaf4ff;--vs-upload-file-border: #e9ebed;--vs-upload-file-bg: #ffffff;--vs-upload-file-color: #2f3941;--vs-upload-file-size-color: #87929d;--vs-upload-remove-color: #cc3340;--vs-upload-remove-hover-color: #8c232c;--vs-upload-error-color: #cc3340;--vs-upload-warning-color: #ad5918;--vs-upload-success-color: #186146;--vs-upload-border-radius: 4px;display:flex;flex-direction:column;font-family:inherit}.vs-upload__label{display:inline-block;margin-bottom:8px;font-size:14px;font-weight:600;color:var(--vs-upload-label-color);line-height:1.4;cursor:default}.vs-upload__hint{margin:-8px 0 8px;font-size:13px;color:var(--vs-upload-hint-color);line-height:1.4}.vs-upload__dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:28px 20px;border:2px dashed var(--vs-upload-dropzone-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-dropzone-bg);color:var(--vs-upload-dropzone-color);cursor:pointer;transition:border-color .2s ease,background .2s ease}.vs-upload__dropzone:hover,.vs-upload__dropzone--dragging{border-color:var(--vs-upload-dropzone-border-dragging);background:var(--vs-upload-dropzone-bg-dragging)}.vs-upload__input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.vs-upload__dropzone-icon{flex-shrink:0}.vs-upload__dropzone-text{font-size:14px;font-weight:500;text-align:center;line-height:1.4}.vs-upload__file-list{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}.vs-upload__file-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--vs-upload-file-border);border-radius:var(--vs-upload-border-radius);background:var(--vs-upload-file-bg);color:var(--vs-upload-file-color)}.vs-upload__file-icon{flex-shrink:0;color:var(--vs-upload-hint-color)}.vs-upload__file-name{flex:1;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vs-upload__file-size{font-size:12px;color:var(--vs-upload-file-size-color);flex-shrink:0}.vs-upload__remove{display:flex;align-items:center;margin-left:4px;background:none;border:none;cursor:pointer;color:var(--vs-upload-remove-color);border-radius:2px;transition:color .15s ease}.vs-upload__remove:hover:not(:disabled){color:var(--vs-upload-remove-hover-color)}.vs-upload__remove:disabled{opacity:.4;cursor:not-allowed}.vs-upload__message{margin:6px 0 0;font-size:12px;line-height:1.4;color:var(--vs-upload-hint-color)}.vs-upload__message--error{color:var(--vs-upload-error-color)}.vs-upload__message--warning{color:var(--vs-upload-warning-color)}.vs-upload__message--success{color:var(--vs-upload-success-color)}.vs-upload--error .vs-upload__dropzone{border-color:var(--vs-upload-error-color)}.vs-upload--warning .vs-upload__dropzone{border-color:var(--vs-upload-warning-color)}.vs-upload--success .vs-upload__dropzone{border-color:var(--vs-upload-success-color)}.vs-upload--compact .vs-upload__dropzone{padding:14px 16px;flex-direction:row;gap:8px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-icon{width:16px;height:16px}.vs-upload--compact .vs-upload__dropzone .vs-upload__dropzone-text{font-size:13px}.vs-upload--compact .vs-upload__file-item{padding:6px 10px}.vs-upload--compact .vs-upload__file-name{font-size:13px}.vs-upload--disabled .vs-upload__dropzone{opacity:.6;cursor:not-allowed}.vs-upload--disabled .vs-upload__dropzone:hover{border-color:var(--vs-upload-dropzone-border);background:var(--vs-upload-dropzone-bg)}
3
+ `,document.head.appendChild(t);const B="",u=(l,o)=>{const a=l.__vccOpts||l;for(const[p,n]of o)a[p]=n;return a};let v=0;const g={name:"VsUpload",inheritAttrs:!1,props:{modelValue:{type:Array,default:()=>[]},label:{type:String},hint:{type:String},accept:{type:String},multiple:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},isCompact:{type:Boolean,default:!1},validation:{type:String,validator:l=>["success","warning","error"].includes(l)},message:{type:String}},emits:["update:modelValue","change","reject"],data(){return{inputId:`vs-upload-${++v}`,isDragging:!1}},computed:{containerClass(){return{"vs-upload--disabled":this.disabled,"vs-upload--compact":this.isCompact,[`vs-upload--${this.validation}`]:!!this.validation}},ariaDescribedBy(){const l=[];return this.hint&&l.push(`${this.inputId}-hint`),this.message&&l.push(`${this.inputId}-message`),l.length?l.join(" "):void 0}},methods:{openFilePicker(){this.disabled||this.$refs.fileInput.click()},onDragOver(){this.disabled||(this.isDragging=!0)},onDragLeave(){this.isDragging=!1},onDrop(l){this.isDragging=!1,!this.disabled&&this.addFiles(l.dataTransfer.files)},onFileInput(l){this.addFiles(l.target.files),l.target.value=""},addFiles(l){if(!l||!l.length)return;const o=Array.from(l),a=this.multiple?[...this.modelValue||[],...o]:[o[0]];this.$emit("update:modelValue",a),this.$emit("change",a)},removeFile(l){const o=[...this.modelValue||[]];o.splice(l,1),this.$emit("update:modelValue",o),this.$emit("change",o)},getFileIconSvg(l){const o=(l.split(".").pop()||"").toLowerCase(),a='xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"';return["jpg","jpeg","png","gif","webp","svg","bmp","ico"].includes(o)?`<svg ${a}><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`:["mp4","mov","avi","mkv","webm"].includes(o)?`<svg ${a}><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`:["mp3","wav","ogg","flac","aac"].includes(o)?`<svg ${a}><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>`:o==="pdf"?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>`:["zip","rar","tar","gz","7z"].includes(o)?'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" focusable="false" viewBox="0 0 16 16" aria-hidden="true" data-garden-id="forms.file.icon" data-garden-version="9.12.6" class="StyledBaseIcon-sc-1moykgb-0 StyledFileIcon-sc-7b3q0c-0 eWlVPJ goYdHe"><path fill="none" stroke="currentColor" stroke-linecap="round" d="M6.5.5v11M5 2.5h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m8-6.3V15c0 .28-.22.5-.5.5H2c-.28 0-.5-.22-.5-.5V1c0-.28.22-.5.5-.5h8.85c.13 0 .26.05.36.15l3.15 3.2c.09.1.14.22.14.35zm-4-3.7V4c0 .28.22.5.5.5h3.5"></path></svg>':["xls","xlsx","csv"].includes(o)?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/><line x1="8" y1="9" x2="10" y2="9"/></svg>`:["ppt","pptx"].includes(o)?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M8 13h5a2 2 0 0 0 0-4H8v8"/></svg>`:["js","ts","jsx","tsx","html","css","scss","json","xml","py","rb","go","java","php","c","cpp","cs","sh","yml","yaml","md"].includes(o)?`<svg ${a}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>`:["txt","doc","docx","rtf"].includes(o)?`<svg ${a}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>`:`<svg ${a}><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>`},formatSize(l){return l===0?"0 B":l<1024?`${l} B`:l<1024*1024?`${(l/1024).toFixed(1)} KB`:`${(l/(1024*1024)).toFixed(1)} MB`}}},h=["for"],f=["id"],m=["id","accept","multiple","disabled","aria-describedby"],_={key:2,class:"vs-upload__file-list",role:"list"},x=["innerHTML"],b=["title"],y={class:"vs-upload__file-size"},z=["aria-label","disabled","onClick"],k=["id"];function w(l,o,a,p,n,s){return e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["vs-upload",s.containerClass])},[a.label?(e.openBlock(),e.createElementBlock("label",{key:0,for:n.inputId,class:"vs-upload__label"},e.toDisplayString(a.label),9,h)):e.createCommentVNode("",!0),a.hint?(e.openBlock(),e.createElementBlock("span",{key:1,class:"vs-upload__hint",id:`${n.inputId}-hint`},e.toDisplayString(a.hint),9,f)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:e.normalizeClass(["vs-upload__dropzone",{"vs-upload__dropzone--dragging":n.isDragging}]),onDragover:o[1]||(o[1]=e.withModifiers((...r)=>s.onDragOver&&s.onDragOver(...r),["prevent"])),onDragleave:o[2]||(o[2]=e.withModifiers((...r)=>s.onDragLeave&&s.onDragLeave(...r),["prevent"])),onDrop:o[3]||(o[3]=e.withModifiers((...r)=>s.onDrop&&s.onDrop(...r),["prevent"])),onClick:o[4]||(o[4]=(...r)=>s.openFilePicker&&s.openFilePicker(...r))},[e.createElementVNode("input",{id:n.inputId,ref:"fileInput",type:"file",class:"vs-upload__input",accept:a.accept,multiple:a.multiple,disabled:a.disabled,"aria-describedby":s.ariaDescribedBy,onChange:o[0]||(o[0]=(...r)=>s.onFileInput&&s.onFileInput(...r))},null,40,m),o[5]||(o[5]=e.createStaticVNode('<svg class="vs-upload__dropzone-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg><span class="vs-upload__dropzone-text">Choose a file or drag and drop here</span>',2))],34),a.modelValue&&a.modelValue.length?(e.openBlock(),e.createElementBlock("ul",_,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.modelValue,(r,c)=>(e.openBlock(),e.createElementBlock("li",{key:`${r.name}-${c}`,class:"vs-upload__file-item"},[e.createElementVNode("span",{class:"vs-upload__file-icon","aria-hidden":"true",innerHTML:s.getFileIconSvg(r.name)},null,8,x),e.createElementVNode("span",{class:"vs-upload__file-name",title:r.name},e.toDisplayString(r.name),9,b),e.createElementVNode("span",y,e.toDisplayString(s.formatSize(r.size)),1),e.createElementVNode("button",{type:"button",class:"vs-upload__remove","aria-label":`Remove ${r.name}`,disabled:a.disabled,onClick:e.withModifiers(C=>s.removeFile(c),["stop"])},[...o[6]||(o[6]=[e.createStaticVNode('<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"></path><path d="M10 11v6"></path><path d="M14 11v6"></path><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"></path></svg>',1)])],8,z)]))),128))])):e.createCommentVNode("",!0),a.message?(e.openBlock(),e.createElementBlock("span",{key:3,class:e.normalizeClass(["vs-upload__message",`vs-upload__message--${a.validation}`]),id:`${n.inputId}-message`},e.toDisplayString(a.message),11,k)):e.createCommentVNode("",!0)],2)}const d=u(g,[["render",w]]),V={install(l){l.component("VsUpload",d)}};i.default=d,i.plugin=V,Object.defineProperties(i,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@vuesimple/vs-upload",
3
+ "version": "3.1.6",
4
+ "description": "A simple vue file upload component with drag-and-drop support.",
5
+ "main": "dist/index.umd.js",
6
+ "module": "dist/index.esm.js",
7
+ "unpkg": "dist/index.min.js",
8
+ "jsdelivr": "dist/index.min.js",
9
+ "scripts": {
10
+ "build": "rm -rfv dist && vite build --config build/vite.config.js"
11
+ },
12
+ "devDependencies": {
13
+ "@vitejs/plugin-vue": "^4.2.3",
14
+ "sass": "^1.54.4",
15
+ "vite": "^4.4.5",
16
+ "vue": "^3.2.37"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/ashwinkshenoy/vue-simple.git"
21
+ },
22
+ "publishConfig": {
23
+ "registry": "https://registry.npmjs.org",
24
+ "access": "public"
25
+ },
26
+ "keywords": [
27
+ "vue",
28
+ "vuejs",
29
+ "upload",
30
+ "file-upload",
31
+ "drag-drop",
32
+ "vs-upload",
33
+ "vue-upload"
34
+ ],
35
+ "author": "Ashwin Shenoy <ashwinkshenoy@gmail.com>",
36
+ "license": "MIT",
37
+ "bugs": {
38
+ "url": "https://github.com/ashwinkshenoy/vue-simple/issues"
39
+ },
40
+ "homepage": "https://github.com/ashwinkshenoy/vue-simple"
41
+ }
package/src/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import VsUpload from './vs-upload.vue';
2
+
3
+ const plugin = {
4
+ install(Vue) {
5
+ Vue.component('VsUpload', VsUpload);
6
+ },
7
+ };
8
+
9
+ export default VsUpload;
10
+ export { plugin };
@@ -0,0 +1,536 @@
1
+ <template>
2
+ <div :class="['vs-upload', containerClass]">
3
+ <!-- Label -->
4
+ <label v-if="label" :for="inputId" class="vs-upload__label">
5
+ {{ label }}
6
+ </label>
7
+
8
+ <!-- Hint -->
9
+ <span v-if="hint" class="vs-upload__hint" :id="`${inputId}-hint`">{{ hint }}</span>
10
+
11
+ <!-- Dropzone -->
12
+ <div
13
+ class="vs-upload__dropzone"
14
+ :class="{ 'vs-upload__dropzone--dragging': isDragging }"
15
+ @dragover.prevent="onDragOver"
16
+ @dragleave.prevent="onDragLeave"
17
+ @drop.prevent="onDrop"
18
+ @click="openFilePicker"
19
+ >
20
+ <input
21
+ :id="inputId"
22
+ ref="fileInput"
23
+ type="file"
24
+ class="vs-upload__input"
25
+ :accept="accept"
26
+ :multiple="multiple"
27
+ :disabled="disabled"
28
+ :aria-describedby="ariaDescribedBy"
29
+ @change="onFileInput"
30
+ />
31
+
32
+ <!-- Upload icon -->
33
+ <svg
34
+ class="vs-upload__dropzone-icon"
35
+ xmlns="http://www.w3.org/2000/svg"
36
+ width="20"
37
+ height="20"
38
+ viewBox="0 0 24 24"
39
+ fill="none"
40
+ stroke="currentColor"
41
+ stroke-width="1.5"
42
+ stroke-linecap="round"
43
+ stroke-linejoin="round"
44
+ aria-hidden="true"
45
+ >
46
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
47
+ <polyline points="17 8 12 3 7 8" />
48
+ <line x1="12" y1="3" x2="12" y2="15" />
49
+ </svg>
50
+
51
+ <span class="vs-upload__dropzone-text">Choose a file or drag and drop here</span>
52
+ </div>
53
+
54
+ <!-- File list -->
55
+ <ul v-if="modelValue && modelValue.length" class="vs-upload__file-list" role="list">
56
+ <li v-for="(file, index) in modelValue" :key="`${file.name}-${index}`" class="vs-upload__file-item">
57
+ <!-- File icon (type-aware) -->
58
+ <span class="vs-upload__file-icon" aria-hidden="true" v-html="getFileIconSvg(file.name)"></span>
59
+
60
+ <span class="vs-upload__file-name" :title="file.name">{{ file.name }}</span>
61
+ <span class="vs-upload__file-size">{{ formatSize(file.size) }}</span>
62
+
63
+ <button
64
+ type="button"
65
+ class="vs-upload__remove"
66
+ :aria-label="`Remove ${file.name}`"
67
+ :disabled="disabled"
68
+ @click.stop="removeFile(index)"
69
+ >
70
+ <!-- Trash icon -->
71
+ <svg
72
+ xmlns="http://www.w3.org/2000/svg"
73
+ width="15"
74
+ height="15"
75
+ viewBox="0 0 24 24"
76
+ fill="none"
77
+ stroke="currentColor"
78
+ stroke-width="1.5"
79
+ stroke-linecap="round"
80
+ stroke-linejoin="round"
81
+ aria-hidden="true"
82
+ >
83
+ <polyline points="3 6 5 6 21 6" />
84
+ <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
85
+ <path d="M10 11v6" />
86
+ <path d="M14 11v6" />
87
+ <path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
88
+ </svg>
89
+ </button>
90
+ </li>
91
+ </ul>
92
+
93
+ <!-- Validation message -->
94
+ <span
95
+ v-if="message"
96
+ class="vs-upload__message"
97
+ :class="`vs-upload__message--${validation}`"
98
+ :id="`${inputId}-message`"
99
+ >
100
+ {{ message }}
101
+ </span>
102
+ </div>
103
+ </template>
104
+
105
+ <script>
106
+ let idCounter = 0;
107
+
108
+ export default {
109
+ name: 'VsUpload',
110
+
111
+ inheritAttrs: false,
112
+
113
+ props: {
114
+ modelValue: {
115
+ type: Array,
116
+ default: () => [],
117
+ },
118
+ label: {
119
+ type: String,
120
+ },
121
+ hint: {
122
+ type: String,
123
+ },
124
+ accept: {
125
+ type: String,
126
+ },
127
+ multiple: {
128
+ type: Boolean,
129
+ default: false,
130
+ },
131
+ disabled: {
132
+ type: Boolean,
133
+ default: false,
134
+ },
135
+ isCompact: {
136
+ type: Boolean,
137
+ default: false,
138
+ },
139
+ validation: {
140
+ type: String,
141
+ validator: val => ['success', 'warning', 'error'].includes(val),
142
+ },
143
+ message: {
144
+ type: String,
145
+ },
146
+ },
147
+
148
+ emits: ['update:modelValue', 'change', 'reject'],
149
+
150
+ data() {
151
+ return {
152
+ inputId: `vs-upload-${++idCounter}`,
153
+ isDragging: false,
154
+ };
155
+ },
156
+
157
+ computed: {
158
+ containerClass() {
159
+ return {
160
+ 'vs-upload--disabled': this.disabled,
161
+ 'vs-upload--compact': this.isCompact,
162
+ [`vs-upload--${this.validation}`]: !!this.validation,
163
+ };
164
+ },
165
+
166
+ ariaDescribedBy() {
167
+ const ids = [];
168
+ if (this.hint) ids.push(`${this.inputId}-hint`);
169
+ if (this.message) ids.push(`${this.inputId}-message`);
170
+ return ids.length ? ids.join(' ') : undefined;
171
+ },
172
+ },
173
+
174
+ methods: {
175
+ openFilePicker() {
176
+ if (!this.disabled) {
177
+ this.$refs.fileInput.click();
178
+ }
179
+ },
180
+
181
+ onDragOver() {
182
+ if (!this.disabled) {
183
+ this.isDragging = true;
184
+ }
185
+ },
186
+
187
+ onDragLeave() {
188
+ this.isDragging = false;
189
+ },
190
+
191
+ onDrop(event) {
192
+ this.isDragging = false;
193
+ if (this.disabled) return;
194
+ this.addFiles(event.dataTransfer.files);
195
+ },
196
+
197
+ onFileInput(event) {
198
+ this.addFiles(event.target.files);
199
+ // Reset so the same file can be selected again
200
+ event.target.value = '';
201
+ },
202
+
203
+ addFiles(fileList) {
204
+ if (!fileList || !fileList.length) return;
205
+ const incoming = Array.from(fileList);
206
+ const updated = this.multiple ? [...(this.modelValue || []), ...incoming] : [incoming[0]];
207
+ this.$emit('update:modelValue', updated);
208
+ this.$emit('change', updated);
209
+ },
210
+
211
+ removeFile(index) {
212
+ const updated = [...(this.modelValue || [])];
213
+ updated.splice(index, 1);
214
+ this.$emit('update:modelValue', updated);
215
+ this.$emit('change', updated);
216
+ },
217
+
218
+ getFileIconSvg(filename) {
219
+ const ext = (filename.split('.').pop() || '').toLowerCase();
220
+ const base = `xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"`;
221
+
222
+ // Image: jpg, jpeg, png, gif, webp, svg, bmp, ico
223
+ if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico'].includes(ext)) {
224
+ return `<svg ${base}><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`;
225
+ }
226
+ // Video: mp4, mov, avi, mkv, webm
227
+ if (['mp4', 'mov', 'avi', 'mkv', 'webm'].includes(ext)) {
228
+ return `<svg ${base}><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`;
229
+ }
230
+ // Audio: mp3, wav, ogg, flac, aac
231
+ if (['mp3', 'wav', 'ogg', 'flac', 'aac'].includes(ext)) {
232
+ return `<svg ${base}><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>`;
233
+ }
234
+ // PDF
235
+ if (ext === 'pdf') {
236
+ return `<svg ${base}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>`;
237
+ }
238
+ // Archive: zip, rar, tar, gz, 7z
239
+ if (['zip', 'rar', 'tar', 'gz', '7z'].includes(ext)) {
240
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" focusable="false" viewBox="0 0 16 16" aria-hidden="true" data-garden-id="forms.file.icon" data-garden-version="9.12.6" class="StyledBaseIcon-sc-1moykgb-0 StyledFileIcon-sc-7b3q0c-0 eWlVPJ goYdHe"><path fill="none" stroke="currentColor" stroke-linecap="round" d="M6.5.5v11M5 2.5h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m0 1H8m-3 1h1.5m8-6.3V15c0 .28-.22.5-.5.5H2c-.28 0-.5-.22-.5-.5V1c0-.28.22-.5.5-.5h8.85c.13 0 .26.05.36.15l3.15 3.2c.09.1.14.22.14.35zm-4-3.7V4c0 .28.22.5.5.5h3.5"></path></svg>`;
241
+ }
242
+ // Spreadsheet: xls, xlsx, csv
243
+ if (['xls', 'xlsx', 'csv'].includes(ext)) {
244
+ return `<svg ${base}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/><line x1="8" y1="9" x2="10" y2="9"/></svg>`;
245
+ }
246
+ // Presentation: ppt, pptx
247
+ if (['ppt', 'pptx'].includes(ext)) {
248
+ return `<svg ${base}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M8 13h5a2 2 0 0 0 0-4H8v8"/></svg>`;
249
+ }
250
+ // Code: js, ts, jsx, tsx, html, css, scss, json, xml, py, rb, go, java, php, etc.
251
+ if (
252
+ [
253
+ 'js',
254
+ 'ts',
255
+ 'jsx',
256
+ 'tsx',
257
+ 'html',
258
+ 'css',
259
+ 'scss',
260
+ 'json',
261
+ 'xml',
262
+ 'py',
263
+ 'rb',
264
+ 'go',
265
+ 'java',
266
+ 'php',
267
+ 'c',
268
+ 'cpp',
269
+ 'cs',
270
+ 'sh',
271
+ 'yml',
272
+ 'yaml',
273
+ 'md',
274
+ ].includes(ext)
275
+ ) {
276
+ return `<svg ${base}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>`;
277
+ }
278
+ // Text / doc: txt, doc, docx, rtf
279
+ if (['txt', 'doc', 'docx', 'rtf'].includes(ext)) {
280
+ return `<svg ${base}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>`;
281
+ }
282
+ // Default: generic file with corner-fold
283
+ return `<svg ${base}><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>`;
284
+ },
285
+
286
+ formatSize(bytes) {
287
+ if (bytes === 0) return '0 B';
288
+ if (bytes < 1024) return `${bytes} B`;
289
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
290
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
291
+ },
292
+ },
293
+ };
294
+ </script>
295
+
296
+ <style lang="scss">
297
+ $el: '.vs-upload';
298
+
299
+ [data-theme='dark'],
300
+ .dark {
301
+ #{$el} {
302
+ --vs-upload-label-color: #b0b8c1;
303
+ --vs-upload-hint-color: #8090a2;
304
+ --vs-upload-dropzone-border: #3a4553;
305
+ --vs-upload-dropzone-bg: #1a1f26;
306
+ --vs-upload-dropzone-color: #4b9fea;
307
+ --vs-upload-dropzone-border-dragging: #42a5f5;
308
+ --vs-upload-dropzone-bg-dragging: #1a2535;
309
+ --vs-upload-file-border: #2a3038;
310
+ --vs-upload-file-bg: #1a1f26;
311
+ --vs-upload-file-color: #b0b8c1;
312
+ --vs-upload-file-size-color: #5a6472;
313
+ --vs-upload-remove-color: #e05252;
314
+ --vs-upload-remove-hover-color: #cc3340;
315
+ }
316
+ }
317
+
318
+ #{$el} {
319
+ --vs-upload-label-color: #2f3941;
320
+ --vs-upload-hint-color: #68737d;
321
+ --vs-upload-dropzone-border: #d8dcde;
322
+ --vs-upload-dropzone-bg: #ffffff;
323
+ --vs-upload-dropzone-color: #1f73b7;
324
+ --vs-upload-dropzone-border-dragging: #1f73b7;
325
+ --vs-upload-dropzone-bg-dragging: #eaf4ff;
326
+ --vs-upload-file-border: #e9ebed;
327
+ --vs-upload-file-bg: #ffffff;
328
+ --vs-upload-file-color: #2f3941;
329
+ --vs-upload-file-size-color: #87929d;
330
+ --vs-upload-remove-color: #cc3340;
331
+ --vs-upload-remove-hover-color: #8c232c;
332
+ --vs-upload-error-color: #cc3340;
333
+ --vs-upload-warning-color: #ad5918;
334
+ --vs-upload-success-color: #186146;
335
+ --vs-upload-border-radius: 4px;
336
+
337
+ display: flex;
338
+ flex-direction: column;
339
+ font-family: inherit;
340
+
341
+ &__label {
342
+ display: inline-block;
343
+ margin-bottom: 8px;
344
+ font-size: 14px;
345
+ font-weight: 600;
346
+ color: var(--vs-upload-label-color);
347
+ line-height: 1.4;
348
+ cursor: default;
349
+ }
350
+
351
+ &__hint {
352
+ margin: -8px 0 8px;
353
+ font-size: 13px;
354
+ color: var(--vs-upload-hint-color);
355
+ line-height: 1.4;
356
+ }
357
+
358
+ &__dropzone {
359
+ position: relative;
360
+ display: flex;
361
+ flex-direction: column;
362
+ align-items: center;
363
+ justify-content: center;
364
+ gap: 8px;
365
+ padding: 28px 20px;
366
+ border: 2px dashed var(--vs-upload-dropzone-border);
367
+ border-radius: var(--vs-upload-border-radius);
368
+ background: var(--vs-upload-dropzone-bg);
369
+ color: var(--vs-upload-dropzone-color);
370
+ cursor: pointer;
371
+ transition:
372
+ border-color 0.2s ease,
373
+ background 0.2s ease;
374
+
375
+ &:hover {
376
+ border-color: var(--vs-upload-dropzone-border-dragging);
377
+ background: var(--vs-upload-dropzone-bg-dragging);
378
+ }
379
+
380
+ &--dragging {
381
+ border-color: var(--vs-upload-dropzone-border-dragging);
382
+ background: var(--vs-upload-dropzone-bg-dragging);
383
+ }
384
+ }
385
+
386
+ &__input {
387
+ position: absolute;
388
+ width: 0;
389
+ height: 0;
390
+ opacity: 0;
391
+ pointer-events: none;
392
+ }
393
+
394
+ &__dropzone-icon {
395
+ flex-shrink: 0;
396
+ }
397
+
398
+ &__dropzone-text {
399
+ font-size: 14px;
400
+ font-weight: 500;
401
+ text-align: center;
402
+ line-height: 1.4;
403
+ }
404
+
405
+ &__file-list {
406
+ list-style: none;
407
+ margin: 8px 0 0;
408
+ padding: 0;
409
+ display: flex;
410
+ flex-direction: column;
411
+ gap: 6px;
412
+ }
413
+
414
+ &__file-item {
415
+ display: flex;
416
+ align-items: center;
417
+ gap: 8px;
418
+ padding: 10px 12px;
419
+ border: 1px solid var(--vs-upload-file-border);
420
+ border-radius: var(--vs-upload-border-radius);
421
+ background: var(--vs-upload-file-bg);
422
+ color: var(--vs-upload-file-color);
423
+ }
424
+
425
+ &__file-icon {
426
+ flex-shrink: 0;
427
+ color: var(--vs-upload-hint-color);
428
+ }
429
+
430
+ &__file-name {
431
+ flex: 1;
432
+ font-size: 14px;
433
+ overflow: hidden;
434
+ text-overflow: ellipsis;
435
+ white-space: nowrap;
436
+ }
437
+
438
+ &__file-size {
439
+ font-size: 12px;
440
+ color: var(--vs-upload-file-size-color);
441
+ flex-shrink: 0;
442
+ }
443
+
444
+ &__remove {
445
+ display: flex;
446
+ align-items: center;
447
+ margin-left: 4px;
448
+ background: none;
449
+ border: none;
450
+ cursor: pointer;
451
+ color: var(--vs-upload-remove-color);
452
+ border-radius: 2px;
453
+ transition: color 0.15s ease;
454
+
455
+ &:hover:not(:disabled) {
456
+ color: var(--vs-upload-remove-hover-color);
457
+ }
458
+
459
+ &:disabled {
460
+ opacity: 0.4;
461
+ cursor: not-allowed;
462
+ }
463
+ }
464
+
465
+ &__message {
466
+ margin: 6px 0 0;
467
+ font-size: 12px;
468
+ line-height: 1.4;
469
+ color: var(--vs-upload-hint-color);
470
+
471
+ &--error {
472
+ color: var(--vs-upload-error-color);
473
+ }
474
+
475
+ &--warning {
476
+ color: var(--vs-upload-warning-color);
477
+ }
478
+
479
+ &--success {
480
+ color: var(--vs-upload-success-color);
481
+ }
482
+ }
483
+
484
+ // Validation state borders on dropzone
485
+ &--error #{$el}__dropzone {
486
+ border-color: var(--vs-upload-error-color);
487
+ }
488
+
489
+ &--warning #{$el}__dropzone {
490
+ border-color: var(--vs-upload-warning-color);
491
+ }
492
+
493
+ &--success #{$el}__dropzone {
494
+ border-color: var(--vs-upload-success-color);
495
+ }
496
+
497
+ // Compact mode — smaller dropzone, tighter file items
498
+ &--compact {
499
+ #{$el}__dropzone {
500
+ padding: 14px 16px;
501
+ flex-direction: row;
502
+ gap: 8px;
503
+
504
+ #{$el}__dropzone-icon {
505
+ width: 16px;
506
+ height: 16px;
507
+ }
508
+
509
+ #{$el}__dropzone-text {
510
+ font-size: 13px;
511
+ }
512
+ }
513
+
514
+ #{$el}__file-item {
515
+ padding: 6px 10px;
516
+ }
517
+
518
+ #{$el}__file-name {
519
+ font-size: 13px;
520
+ }
521
+ }
522
+
523
+ // Disabled state
524
+ &--disabled {
525
+ #{$el}__dropzone {
526
+ opacity: 0.6;
527
+ cursor: not-allowed;
528
+
529
+ &:hover {
530
+ border-color: var(--vs-upload-dropzone-border);
531
+ background: var(--vs-upload-dropzone-bg);
532
+ }
533
+ }
534
+ }
535
+ }
536
+ </style>