@duskmoon-dev/el-file-upload 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +496 -0
- package/dist/cjs/index.js.map +11 -0
- package/dist/cjs/register.js +499 -0
- package/dist/cjs/register.js.map +12 -0
- package/dist/esm/index.js +464 -0
- package/dist/esm/index.js.map +11 -0
- package/dist/esm/register.js +463 -0
- package/dist/esm/register.js.map +12 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/el-dm-file-upload.d.ts +101 -0
- package/dist/types/el-dm-file-upload.d.ts.map +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/register.d.ts +2 -0
- package/dist/types/register.d.ts.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var exports_src = {};
|
|
31
|
+
__export(exports_src, {
|
|
32
|
+
register: () => register,
|
|
33
|
+
ElDmFileUpload: () => ElDmFileUpload
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(exports_src);
|
|
36
|
+
|
|
37
|
+
// src/el-dm-file-upload.ts
|
|
38
|
+
var import_el_core = require("@duskmoon-dev/el-core");
|
|
39
|
+
var import_file_upload = require("@duskmoon-dev/core/components/file-upload");
|
|
40
|
+
var SIZE_CLASSES = {
|
|
41
|
+
sm: "file-upload-sm",
|
|
42
|
+
md: "",
|
|
43
|
+
lg: "file-upload-lg"
|
|
44
|
+
};
|
|
45
|
+
var coreStyles = import_file_upload.css.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
|
|
46
|
+
var styles = import_el_core.css`
|
|
47
|
+
:host {
|
|
48
|
+
display: block;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:host([hidden]) {
|
|
52
|
+
display: none !important;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
${coreStyles}
|
|
56
|
+
|
|
57
|
+
/* Web component specific adjustments */
|
|
58
|
+
.file-upload {
|
|
59
|
+
font-family: inherit;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.file-upload-dropzone {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
gap: 0.5rem;
|
|
68
|
+
min-height: 150px;
|
|
69
|
+
padding: 2rem;
|
|
70
|
+
border: 2px dashed var(--color-outline, #ccc);
|
|
71
|
+
border-radius: 0.5rem;
|
|
72
|
+
background-color: var(--color-surface-container, #f5f5f5);
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
transition:
|
|
75
|
+
border-color 0.2s,
|
|
76
|
+
background-color 0.2s;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.file-upload-dropzone:hover {
|
|
80
|
+
border-color: var(--color-primary);
|
|
81
|
+
background-color: var(--color-surface-container-high, #e8e8e8);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.file-upload-dropzone.dragging {
|
|
85
|
+
border-color: var(--color-primary);
|
|
86
|
+
background-color: var(--color-primary);
|
|
87
|
+
background-color: rgba(var(--color-primary-rgb, 98, 0, 238), 0.1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.file-upload-input {
|
|
91
|
+
display: none;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.file-upload-icon {
|
|
95
|
+
font-size: 2.5rem;
|
|
96
|
+
color: var(--color-on-surface);
|
|
97
|
+
opacity: 0.5;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.file-upload-text {
|
|
101
|
+
text-align: center;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.file-upload-title {
|
|
105
|
+
font-size: 1rem;
|
|
106
|
+
font-weight: 500;
|
|
107
|
+
color: var(--color-on-surface);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.file-upload-subtitle {
|
|
111
|
+
font-size: 0.875rem;
|
|
112
|
+
color: var(--color-on-surface);
|
|
113
|
+
opacity: 0.7;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.file-upload-browse {
|
|
117
|
+
color: var(--color-primary);
|
|
118
|
+
text-decoration: underline;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* File list */
|
|
123
|
+
.file-upload-list {
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
gap: 0.5rem;
|
|
127
|
+
margin-top: 1rem;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.file-upload-item {
|
|
131
|
+
display: flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
gap: 0.75rem;
|
|
134
|
+
padding: 0.75rem;
|
|
135
|
+
background-color: var(--color-surface-container, #f5f5f5);
|
|
136
|
+
border-radius: 0.375rem;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.file-upload-item-icon {
|
|
140
|
+
font-size: 1.5rem;
|
|
141
|
+
color: var(--color-on-surface);
|
|
142
|
+
opacity: 0.7;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.file-upload-item-info {
|
|
146
|
+
flex: 1;
|
|
147
|
+
min-width: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.file-upload-item-name {
|
|
151
|
+
font-size: 0.875rem;
|
|
152
|
+
font-weight: 500;
|
|
153
|
+
color: var(--color-on-surface);
|
|
154
|
+
white-space: nowrap;
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
text-overflow: ellipsis;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.file-upload-item-size {
|
|
160
|
+
font-size: 0.75rem;
|
|
161
|
+
color: var(--color-on-surface);
|
|
162
|
+
opacity: 0.7;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.file-upload-item-remove {
|
|
166
|
+
display: flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
justify-content: center;
|
|
169
|
+
width: 1.5rem;
|
|
170
|
+
height: 1.5rem;
|
|
171
|
+
padding: 0;
|
|
172
|
+
border: none;
|
|
173
|
+
border-radius: 50%;
|
|
174
|
+
background-color: transparent;
|
|
175
|
+
color: var(--color-on-surface);
|
|
176
|
+
opacity: 0.5;
|
|
177
|
+
cursor: pointer;
|
|
178
|
+
transition:
|
|
179
|
+
opacity 0.2s,
|
|
180
|
+
background-color 0.2s;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.file-upload-item-remove:hover {
|
|
184
|
+
opacity: 1;
|
|
185
|
+
background-color: var(--color-error);
|
|
186
|
+
color: var(--color-on-error, white);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Preview grid */
|
|
190
|
+
.file-upload-preview {
|
|
191
|
+
display: grid;
|
|
192
|
+
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
|
193
|
+
gap: 0.75rem;
|
|
194
|
+
margin-top: 1rem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.file-upload-preview-item {
|
|
198
|
+
position: relative;
|
|
199
|
+
aspect-ratio: 1;
|
|
200
|
+
border-radius: 0.375rem;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
background-color: var(--color-surface-container, #f5f5f5);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.file-upload-preview-image {
|
|
206
|
+
width: 100%;
|
|
207
|
+
height: 100%;
|
|
208
|
+
object-fit: cover;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.file-upload-preview-remove {
|
|
212
|
+
position: absolute;
|
|
213
|
+
top: 0.25rem;
|
|
214
|
+
right: 0.25rem;
|
|
215
|
+
display: flex;
|
|
216
|
+
align-items: center;
|
|
217
|
+
justify-content: center;
|
|
218
|
+
width: 1.5rem;
|
|
219
|
+
height: 1.5rem;
|
|
220
|
+
padding: 0;
|
|
221
|
+
border: none;
|
|
222
|
+
border-radius: 50%;
|
|
223
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
224
|
+
color: white;
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
opacity: 0;
|
|
227
|
+
transition: opacity 0.2s;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.file-upload-preview-item:hover .file-upload-preview-remove {
|
|
231
|
+
opacity: 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Size variants */
|
|
235
|
+
.file-upload-sm .file-upload-dropzone {
|
|
236
|
+
min-height: 100px;
|
|
237
|
+
padding: 1rem;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.file-upload-lg .file-upload-dropzone {
|
|
241
|
+
min-height: 200px;
|
|
242
|
+
padding: 3rem;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* Compact variant */
|
|
246
|
+
.file-upload-compact .file-upload-dropzone {
|
|
247
|
+
flex-direction: row;
|
|
248
|
+
min-height: auto;
|
|
249
|
+
padding: 1rem;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Disabled state */
|
|
253
|
+
:host([disabled]) .file-upload-dropzone {
|
|
254
|
+
opacity: 0.5;
|
|
255
|
+
cursor: not-allowed;
|
|
256
|
+
pointer-events: none;
|
|
257
|
+
}
|
|
258
|
+
`;
|
|
259
|
+
|
|
260
|
+
class ElDmFileUpload extends import_el_core.BaseElement {
|
|
261
|
+
static properties = {
|
|
262
|
+
accept: { type: String, reflect: true },
|
|
263
|
+
multiple: { type: Boolean, reflect: true },
|
|
264
|
+
disabled: { type: Boolean, reflect: true },
|
|
265
|
+
maxSize: { type: Number, reflect: true, attribute: "max-size" },
|
|
266
|
+
maxFiles: { type: Number, reflect: true, attribute: "max-files" },
|
|
267
|
+
showPreview: { type: Boolean, reflect: true, attribute: "show-preview" },
|
|
268
|
+
compact: { type: Boolean, reflect: true },
|
|
269
|
+
size: { type: String, reflect: true }
|
|
270
|
+
};
|
|
271
|
+
_files = [];
|
|
272
|
+
constructor() {
|
|
273
|
+
super();
|
|
274
|
+
this.attachStyles(styles);
|
|
275
|
+
}
|
|
276
|
+
get files() {
|
|
277
|
+
return this._files;
|
|
278
|
+
}
|
|
279
|
+
_getClasses() {
|
|
280
|
+
const classes = ["file-upload"];
|
|
281
|
+
if (this.size && SIZE_CLASSES[this.size]) {
|
|
282
|
+
classes.push(SIZE_CLASSES[this.size]);
|
|
283
|
+
}
|
|
284
|
+
if (this.compact) {
|
|
285
|
+
classes.push("file-upload-compact");
|
|
286
|
+
}
|
|
287
|
+
return classes.join(" ");
|
|
288
|
+
}
|
|
289
|
+
_formatFileSize(bytes) {
|
|
290
|
+
if (bytes === 0)
|
|
291
|
+
return "0 Bytes";
|
|
292
|
+
const k = 1024;
|
|
293
|
+
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
294
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
295
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
296
|
+
}
|
|
297
|
+
_generateId() {
|
|
298
|
+
return Math.random().toString(36).substring(2, 11);
|
|
299
|
+
}
|
|
300
|
+
_handleDragOver(e) {
|
|
301
|
+
e.preventDefault();
|
|
302
|
+
if (this.disabled)
|
|
303
|
+
return;
|
|
304
|
+
const dropzone = this.shadowRoot?.querySelector(".file-upload-dropzone");
|
|
305
|
+
dropzone?.classList.add("dragging");
|
|
306
|
+
}
|
|
307
|
+
_handleDragLeave(e) {
|
|
308
|
+
e.preventDefault();
|
|
309
|
+
const dropzone = this.shadowRoot?.querySelector(".file-upload-dropzone");
|
|
310
|
+
dropzone?.classList.remove("dragging");
|
|
311
|
+
}
|
|
312
|
+
_handleDrop(e) {
|
|
313
|
+
e.preventDefault();
|
|
314
|
+
if (this.disabled)
|
|
315
|
+
return;
|
|
316
|
+
const dropzone = this.shadowRoot?.querySelector(".file-upload-dropzone");
|
|
317
|
+
dropzone?.classList.remove("dragging");
|
|
318
|
+
const files = e.dataTransfer?.files;
|
|
319
|
+
if (files) {
|
|
320
|
+
this._processFiles(files);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
_handleClick() {
|
|
324
|
+
if (this.disabled)
|
|
325
|
+
return;
|
|
326
|
+
const input = this.shadowRoot?.querySelector(".file-upload-input");
|
|
327
|
+
input?.click();
|
|
328
|
+
}
|
|
329
|
+
_handleInputChange(e) {
|
|
330
|
+
const input = e.target;
|
|
331
|
+
if (input.files) {
|
|
332
|
+
this._processFiles(input.files);
|
|
333
|
+
}
|
|
334
|
+
input.value = "";
|
|
335
|
+
}
|
|
336
|
+
_processFiles(fileList) {
|
|
337
|
+
const newFiles = [];
|
|
338
|
+
for (let i = 0;i < fileList.length; i++) {
|
|
339
|
+
const file = fileList[i];
|
|
340
|
+
if (this.maxFiles && this._files.length + newFiles.length >= this.maxFiles) {
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
if (this.maxSize && file.size > this.maxSize) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
const uploadedFile = {
|
|
347
|
+
file,
|
|
348
|
+
id: this._generateId()
|
|
349
|
+
};
|
|
350
|
+
if (this.showPreview && file.type.startsWith("image/")) {
|
|
351
|
+
uploadedFile.preview = URL.createObjectURL(file);
|
|
352
|
+
}
|
|
353
|
+
newFiles.push(uploadedFile);
|
|
354
|
+
}
|
|
355
|
+
if (this.multiple) {
|
|
356
|
+
this._files = [...this._files, ...newFiles];
|
|
357
|
+
} else {
|
|
358
|
+
this._files.forEach((f) => {
|
|
359
|
+
if (f.preview)
|
|
360
|
+
URL.revokeObjectURL(f.preview);
|
|
361
|
+
});
|
|
362
|
+
this._files = newFiles.slice(0, 1);
|
|
363
|
+
}
|
|
364
|
+
this._updateFileList();
|
|
365
|
+
this.emit("change", { files: this._files.map((f) => f.file) });
|
|
366
|
+
}
|
|
367
|
+
_removeFile(id) {
|
|
368
|
+
const file = this._files.find((f) => f.id === id);
|
|
369
|
+
if (file?.preview) {
|
|
370
|
+
URL.revokeObjectURL(file.preview);
|
|
371
|
+
}
|
|
372
|
+
this._files = this._files.filter((f) => f.id !== id);
|
|
373
|
+
this._updateFileList();
|
|
374
|
+
this.emit("remove", { files: this._files.map((f) => f.file) });
|
|
375
|
+
this.emit("change", { files: this._files.map((f) => f.file) });
|
|
376
|
+
}
|
|
377
|
+
_updateFileList() {
|
|
378
|
+
const listContainer = this.shadowRoot?.querySelector(".file-upload-list");
|
|
379
|
+
const previewContainer = this.shadowRoot?.querySelector(".file-upload-preview");
|
|
380
|
+
if (this.showPreview && previewContainer) {
|
|
381
|
+
previewContainer.innerHTML = this._files.map((f) => `
|
|
382
|
+
<div class="file-upload-preview-item" data-id="${f.id}">
|
|
383
|
+
${f.preview ? `<img class="file-upload-preview-image" src="${f.preview}" alt="${f.file.name}">` : ""}
|
|
384
|
+
<button class="file-upload-preview-remove" type="button" aria-label="Remove file">
|
|
385
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
386
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
387
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
388
|
+
</svg>
|
|
389
|
+
</button>
|
|
390
|
+
</div>
|
|
391
|
+
`).join("");
|
|
392
|
+
previewContainer.querySelectorAll(".file-upload-preview-remove").forEach((btn, index) => {
|
|
393
|
+
btn.addEventListener("click", (e) => {
|
|
394
|
+
e.stopPropagation();
|
|
395
|
+
this._removeFile(this._files[index].id);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
} else if (listContainer) {
|
|
399
|
+
listContainer.innerHTML = this._files.map((f) => `
|
|
400
|
+
<div class="file-upload-item" data-id="${f.id}">
|
|
401
|
+
<span class="file-upload-item-icon">
|
|
402
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
403
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
|
404
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
405
|
+
</svg>
|
|
406
|
+
</span>
|
|
407
|
+
<div class="file-upload-item-info">
|
|
408
|
+
<div class="file-upload-item-name">${f.file.name}</div>
|
|
409
|
+
<div class="file-upload-item-size">${this._formatFileSize(f.file.size)}</div>
|
|
410
|
+
</div>
|
|
411
|
+
<button class="file-upload-item-remove" type="button" aria-label="Remove file">
|
|
412
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
413
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
414
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
415
|
+
</svg>
|
|
416
|
+
</button>
|
|
417
|
+
</div>
|
|
418
|
+
`).join("");
|
|
419
|
+
listContainer.querySelectorAll(".file-upload-item-remove").forEach((btn, index) => {
|
|
420
|
+
btn.addEventListener("click", (e) => {
|
|
421
|
+
e.stopPropagation();
|
|
422
|
+
this._removeFile(this._files[index].id);
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
clear() {
|
|
428
|
+
this._files.forEach((f) => {
|
|
429
|
+
if (f.preview)
|
|
430
|
+
URL.revokeObjectURL(f.preview);
|
|
431
|
+
});
|
|
432
|
+
this._files = [];
|
|
433
|
+
this._updateFileList();
|
|
434
|
+
this.emit("change", { files: [] });
|
|
435
|
+
}
|
|
436
|
+
render() {
|
|
437
|
+
const classes = this._getClasses();
|
|
438
|
+
return `
|
|
439
|
+
<div class="${classes}" part="file-upload">
|
|
440
|
+
<input
|
|
441
|
+
type="file"
|
|
442
|
+
class="file-upload-input"
|
|
443
|
+
${this.accept ? `accept="${this.accept}"` : ""}
|
|
444
|
+
${this.multiple ? "multiple" : ""}
|
|
445
|
+
${this.disabled ? "disabled" : ""}
|
|
446
|
+
>
|
|
447
|
+
<div class="file-upload-dropzone" part="dropzone">
|
|
448
|
+
<span class="file-upload-icon">
|
|
449
|
+
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
450
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
451
|
+
<polyline points="17 8 12 3 7 8"></polyline>
|
|
452
|
+
<line x1="12" y1="3" x2="12" y2="15"></line>
|
|
453
|
+
</svg>
|
|
454
|
+
</span>
|
|
455
|
+
<div class="file-upload-text">
|
|
456
|
+
<div class="file-upload-title">
|
|
457
|
+
Drag & drop files here or <span class="file-upload-browse">browse</span>
|
|
458
|
+
</div>
|
|
459
|
+
<div class="file-upload-subtitle">
|
|
460
|
+
${this.accept ? `Accepted: ${this.accept}` : "All file types accepted"}
|
|
461
|
+
${this.maxSize ? ` • Max ${this._formatFileSize(this.maxSize)}` : ""}
|
|
462
|
+
</div>
|
|
463
|
+
</div>
|
|
464
|
+
</div>
|
|
465
|
+
${this.showPreview ? '<div class="file-upload-preview" part="preview"></div>' : '<div class="file-upload-list" part="file-list"></div>'}
|
|
466
|
+
</div>
|
|
467
|
+
`;
|
|
468
|
+
}
|
|
469
|
+
update() {
|
|
470
|
+
super.update();
|
|
471
|
+
const dropzone = this.shadowRoot?.querySelector(".file-upload-dropzone");
|
|
472
|
+
const input = this.shadowRoot?.querySelector(".file-upload-input");
|
|
473
|
+
dropzone?.addEventListener("dragover", (e) => this._handleDragOver(e));
|
|
474
|
+
dropzone?.addEventListener("dragleave", (e) => this._handleDragLeave(e));
|
|
475
|
+
dropzone?.addEventListener("drop", (e) => this._handleDrop(e));
|
|
476
|
+
dropzone?.addEventListener("click", () => this._handleClick());
|
|
477
|
+
input?.addEventListener("change", (e) => this._handleInputChange(e));
|
|
478
|
+
}
|
|
479
|
+
disconnectedCallback() {
|
|
480
|
+
super.disconnectedCallback?.();
|
|
481
|
+
this._files.forEach((f) => {
|
|
482
|
+
if (f.preview)
|
|
483
|
+
URL.revokeObjectURL(f.preview);
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/index.ts
|
|
489
|
+
function register() {
|
|
490
|
+
if (!customElements.get("el-dm-file-upload")) {
|
|
491
|
+
customElements.define("el-dm-file-upload", ElDmFileUpload);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
//# debugId=F7C95C9A4BF55F7E64756E2164756E21
|
|
496
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/el-dm-file-upload.ts", "../../src/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * DuskMoon File Upload Element\n *\n * A drag-and-drop file upload component with file list and preview support.\n * Uses styles from @duskmoon-dev/core for consistent theming.\n *\n * @element el-dm-file-upload\n *\n * @attr {string} accept - File type filter (e.g., \"image/*,.pdf\")\n * @attr {boolean} multiple - Allow multiple files\n * @attr {boolean} disabled - Whether the upload is disabled\n * @attr {number} max-size - Maximum file size in bytes\n * @attr {number} max-files - Maximum number of files\n * @attr {boolean} show-preview - Show image previews\n * @attr {boolean} compact - Use compact layout\n * @attr {string} size - Size: sm, md, lg\n *\n * @slot - Default slot for custom dropzone content\n *\n * @csspart dropzone - The dropzone area\n * @csspart file-list - The file list container\n *\n * @fires change - Fired when files are selected\n * @fires remove - Fired when a file is removed\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\nimport { css as fileUploadCSS } from '@duskmoon-dev/core/components/file-upload';\n\nexport type FileUploadSize = 'sm' | 'md' | 'lg';\n\nexport interface UploadedFile {\n file: File;\n id: string;\n preview?: string;\n}\n\nconst SIZE_CLASSES: Record<string, string> = {\n sm: 'file-upload-sm',\n md: '',\n lg: 'file-upload-lg',\n};\n\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = fileUploadCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\n\nconst styles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n ${coreStyles}\n\n /* Web component specific adjustments */\n .file-upload {\n font-family: inherit;\n }\n\n .file-upload-dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: 150px;\n padding: 2rem;\n border: 2px dashed var(--color-outline, #ccc);\n border-radius: 0.5rem;\n background-color: var(--color-surface-container, #f5f5f5);\n cursor: pointer;\n transition:\n border-color 0.2s,\n background-color 0.2s;\n }\n\n .file-upload-dropzone:hover {\n border-color: var(--color-primary);\n background-color: var(--color-surface-container-high, #e8e8e8);\n }\n\n .file-upload-dropzone.dragging {\n border-color: var(--color-primary);\n background-color: var(--color-primary);\n background-color: rgba(var(--color-primary-rgb, 98, 0, 238), 0.1);\n }\n\n .file-upload-input {\n display: none;\n }\n\n .file-upload-icon {\n font-size: 2.5rem;\n color: var(--color-on-surface);\n opacity: 0.5;\n }\n\n .file-upload-text {\n text-align: center;\n }\n\n .file-upload-title {\n font-size: 1rem;\n font-weight: 500;\n color: var(--color-on-surface);\n }\n\n .file-upload-subtitle {\n font-size: 0.875rem;\n color: var(--color-on-surface);\n opacity: 0.7;\n }\n\n .file-upload-browse {\n color: var(--color-primary);\n text-decoration: underline;\n cursor: pointer;\n }\n\n /* File list */\n .file-upload-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n margin-top: 1rem;\n }\n\n .file-upload-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem;\n background-color: var(--color-surface-container, #f5f5f5);\n border-radius: 0.375rem;\n }\n\n .file-upload-item-icon {\n font-size: 1.5rem;\n color: var(--color-on-surface);\n opacity: 0.7;\n }\n\n .file-upload-item-info {\n flex: 1;\n min-width: 0;\n }\n\n .file-upload-item-name {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--color-on-surface);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .file-upload-item-size {\n font-size: 0.75rem;\n color: var(--color-on-surface);\n opacity: 0.7;\n }\n\n .file-upload-item-remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n padding: 0;\n border: none;\n border-radius: 50%;\n background-color: transparent;\n color: var(--color-on-surface);\n opacity: 0.5;\n cursor: pointer;\n transition:\n opacity 0.2s,\n background-color 0.2s;\n }\n\n .file-upload-item-remove:hover {\n opacity: 1;\n background-color: var(--color-error);\n color: var(--color-on-error, white);\n }\n\n /* Preview grid */\n .file-upload-preview {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));\n gap: 0.75rem;\n margin-top: 1rem;\n }\n\n .file-upload-preview-item {\n position: relative;\n aspect-ratio: 1;\n border-radius: 0.375rem;\n overflow: hidden;\n background-color: var(--color-surface-container, #f5f5f5);\n }\n\n .file-upload-preview-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n .file-upload-preview-remove {\n position: absolute;\n top: 0.25rem;\n right: 0.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n padding: 0;\n border: none;\n border-radius: 50%;\n background-color: rgba(0, 0, 0, 0.5);\n color: white;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s;\n }\n\n .file-upload-preview-item:hover .file-upload-preview-remove {\n opacity: 1;\n }\n\n /* Size variants */\n .file-upload-sm .file-upload-dropzone {\n min-height: 100px;\n padding: 1rem;\n }\n\n .file-upload-lg .file-upload-dropzone {\n min-height: 200px;\n padding: 3rem;\n }\n\n /* Compact variant */\n .file-upload-compact .file-upload-dropzone {\n flex-direction: row;\n min-height: auto;\n padding: 1rem;\n }\n\n /* Disabled state */\n :host([disabled]) .file-upload-dropzone {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n }\n`;\n\nexport class ElDmFileUpload extends BaseElement {\n static properties = {\n accept: { type: String, reflect: true },\n multiple: { type: Boolean, reflect: true },\n disabled: { type: Boolean, reflect: true },\n maxSize: { type: Number, reflect: true, attribute: 'max-size' },\n maxFiles: { type: Number, reflect: true, attribute: 'max-files' },\n showPreview: { type: Boolean, reflect: true, attribute: 'show-preview' },\n compact: { type: Boolean, reflect: true },\n size: { type: String, reflect: true },\n };\n\n declare accept: string;\n declare multiple: boolean;\n declare disabled: boolean;\n declare maxSize: number;\n declare maxFiles: number;\n declare showPreview: boolean;\n declare compact: boolean;\n declare size: FileUploadSize;\n\n private _files: UploadedFile[] = [];\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n get files(): UploadedFile[] {\n return this._files;\n }\n\n private _getClasses(): string {\n const classes = ['file-upload'];\n\n if (this.size && SIZE_CLASSES[this.size]) {\n classes.push(SIZE_CLASSES[this.size]);\n }\n\n if (this.compact) {\n classes.push('file-upload-compact');\n }\n\n return classes.join(' ');\n }\n\n private _formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n }\n\n private _generateId(): string {\n return Math.random().toString(36).substring(2, 11);\n }\n\n private _handleDragOver(e: DragEvent): void {\n e.preventDefault();\n if (this.disabled) return;\n const dropzone = this.shadowRoot?.querySelector('.file-upload-dropzone');\n dropzone?.classList.add('dragging');\n }\n\n private _handleDragLeave(e: DragEvent): void {\n e.preventDefault();\n const dropzone = this.shadowRoot?.querySelector('.file-upload-dropzone');\n dropzone?.classList.remove('dragging');\n }\n\n private _handleDrop(e: DragEvent): void {\n e.preventDefault();\n if (this.disabled) return;\n\n const dropzone = this.shadowRoot?.querySelector('.file-upload-dropzone');\n dropzone?.classList.remove('dragging');\n\n const files = e.dataTransfer?.files;\n if (files) {\n this._processFiles(files);\n }\n }\n\n private _handleClick(): void {\n if (this.disabled) return;\n const input = this.shadowRoot?.querySelector('.file-upload-input') as HTMLInputElement;\n input?.click();\n }\n\n private _handleInputChange(e: Event): void {\n const input = e.target as HTMLInputElement;\n if (input.files) {\n this._processFiles(input.files);\n }\n // Reset input so the same file can be selected again\n input.value = '';\n }\n\n private _processFiles(fileList: FileList): void {\n const newFiles: UploadedFile[] = [];\n\n for (let i = 0; i < fileList.length; i++) {\n const file = fileList[i];\n\n // Check max files\n if (this.maxFiles && this._files.length + newFiles.length >= this.maxFiles) {\n break;\n }\n\n // Check file size\n if (this.maxSize && file.size > this.maxSize) {\n continue;\n }\n\n const uploadedFile: UploadedFile = {\n file,\n id: this._generateId(),\n };\n\n // Generate preview for images\n if (this.showPreview && file.type.startsWith('image/')) {\n uploadedFile.preview = URL.createObjectURL(file);\n }\n\n newFiles.push(uploadedFile);\n }\n\n if (this.multiple) {\n this._files = [...this._files, ...newFiles];\n } else {\n // Clean up old previews\n this._files.forEach((f) => {\n if (f.preview) URL.revokeObjectURL(f.preview);\n });\n this._files = newFiles.slice(0, 1);\n }\n\n this._updateFileList();\n this.emit('change', { files: this._files.map((f) => f.file) });\n }\n\n private _removeFile(id: string): void {\n const file = this._files.find((f) => f.id === id);\n if (file?.preview) {\n URL.revokeObjectURL(file.preview);\n }\n\n this._files = this._files.filter((f) => f.id !== id);\n this._updateFileList();\n this.emit('remove', { files: this._files.map((f) => f.file) });\n this.emit('change', { files: this._files.map((f) => f.file) });\n }\n\n private _updateFileList(): void {\n const listContainer = this.shadowRoot?.querySelector('.file-upload-list');\n const previewContainer = this.shadowRoot?.querySelector('.file-upload-preview');\n\n if (this.showPreview && previewContainer) {\n previewContainer.innerHTML = this._files\n .map(\n (f) => `\n <div class=\"file-upload-preview-item\" data-id=\"${f.id}\">\n ${f.preview ? `<img class=\"file-upload-preview-image\" src=\"${f.preview}\" alt=\"${f.file.name}\">` : ''}\n <button class=\"file-upload-preview-remove\" type=\"button\" aria-label=\"Remove file\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n `,\n )\n .join('');\n\n previewContainer.querySelectorAll('.file-upload-preview-remove').forEach((btn, index) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._removeFile(this._files[index].id);\n });\n });\n } else if (listContainer) {\n listContainer.innerHTML = this._files\n .map(\n (f) => `\n <div class=\"file-upload-item\" data-id=\"${f.id}\">\n <span class=\"file-upload-item-icon\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"></path>\n <polyline points=\"14 2 14 8 20 8\"></polyline>\n </svg>\n </span>\n <div class=\"file-upload-item-info\">\n <div class=\"file-upload-item-name\">${f.file.name}</div>\n <div class=\"file-upload-item-size\">${this._formatFileSize(f.file.size)}</div>\n </div>\n <button class=\"file-upload-item-remove\" type=\"button\" aria-label=\"Remove file\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n `,\n )\n .join('');\n\n listContainer.querySelectorAll('.file-upload-item-remove').forEach((btn, index) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._removeFile(this._files[index].id);\n });\n });\n }\n }\n\n /**\n * Clear all files\n */\n clear(): void {\n this._files.forEach((f) => {\n if (f.preview) URL.revokeObjectURL(f.preview);\n });\n this._files = [];\n this._updateFileList();\n this.emit('change', { files: [] });\n }\n\n render(): string {\n const classes = this._getClasses();\n\n return `\n <div class=\"${classes}\" part=\"file-upload\">\n <input\n type=\"file\"\n class=\"file-upload-input\"\n ${this.accept ? `accept=\"${this.accept}\"` : ''}\n ${this.multiple ? 'multiple' : ''}\n ${this.disabled ? 'disabled' : ''}\n >\n <div class=\"file-upload-dropzone\" part=\"dropzone\">\n <span class=\"file-upload-icon\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path>\n <polyline points=\"17 8 12 3 7 8\"></polyline>\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"></line>\n </svg>\n </span>\n <div class=\"file-upload-text\">\n <div class=\"file-upload-title\">\n Drag & drop files here or <span class=\"file-upload-browse\">browse</span>\n </div>\n <div class=\"file-upload-subtitle\">\n ${this.accept ? `Accepted: ${this.accept}` : 'All file types accepted'}\n ${this.maxSize ? ` • Max ${this._formatFileSize(this.maxSize)}` : ''}\n </div>\n </div>\n </div>\n ${this.showPreview ? '<div class=\"file-upload-preview\" part=\"preview\"></div>' : '<div class=\"file-upload-list\" part=\"file-list\"></div>'}\n </div>\n `;\n }\n\n update(): void {\n super.update();\n\n const dropzone = this.shadowRoot?.querySelector('.file-upload-dropzone');\n const input = this.shadowRoot?.querySelector('.file-upload-input');\n\n dropzone?.addEventListener('dragover', ((e: DragEvent) =>\n this._handleDragOver(e)) as EventListener);\n dropzone?.addEventListener('dragleave', ((e: DragEvent) =>\n this._handleDragLeave(e)) as EventListener);\n dropzone?.addEventListener('drop', ((e: DragEvent) => this._handleDrop(e)) as EventListener);\n dropzone?.addEventListener('click', () => this._handleClick());\n input?.addEventListener('change', ((e: Event) => this._handleInputChange(e)) as EventListener);\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback?.();\n // Clean up object URLs\n this._files.forEach((f) => {\n if (f.preview) URL.revokeObjectURL(f.preview);\n });\n }\n}\n",
|
|
6
|
+
"/**\n * @duskmoon-dev/el-file-upload\n *\n * DuskMoon File Upload custom element\n */\n\nimport { ElDmFileUpload } from './el-dm-file-upload.js';\n\nexport { ElDmFileUpload };\nexport type { FileUploadSize, UploadedFile } from './el-dm-file-upload.js';\n\n/**\n * Register the el-dm-file-upload custom element\n *\n * @example\n * ```ts\n * import { register } from '@duskmoon-dev/el-file-upload';\n * register();\n * ```\n */\nexport function register(): void {\n if (!customElements.get('el-dm-file-upload')) {\n customElements.define('el-dm-file-upload', ElDmFileUpload);\n }\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "F7C95C9A4BF55F7E64756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|