@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.
@@ -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
+ }