@liwe3/webcomponents 1.0.2 → 1.1.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.
Files changed (52) hide show
  1. package/dist/AITextEditor.d.ts +173 -0
  2. package/dist/AITextEditor.d.ts.map +1 -0
  3. package/dist/ChunkUploader.d.ts +103 -0
  4. package/dist/ChunkUploader.d.ts.map +1 -0
  5. package/dist/ChunkUploader.js +614 -0
  6. package/dist/ChunkUploader.js.map +1 -0
  7. package/dist/ContainerBox.d.ts +112 -0
  8. package/dist/ContainerBox.d.ts.map +1 -0
  9. package/dist/ContainerBox.js +359 -0
  10. package/dist/ContainerBox.js.map +1 -0
  11. package/dist/DateSelector.d.ts +103 -0
  12. package/dist/DateSelector.d.ts.map +1 -0
  13. package/dist/DateSelector.js +372 -0
  14. package/dist/DateSelector.js.map +1 -0
  15. package/dist/Drawer.d.ts +63 -0
  16. package/dist/Drawer.d.ts.map +1 -0
  17. package/dist/Drawer.js +340 -0
  18. package/dist/Drawer.js.map +1 -0
  19. package/dist/ImageView.d.ts +42 -0
  20. package/dist/ImageView.d.ts.map +1 -0
  21. package/dist/ImageView.js +209 -0
  22. package/dist/ImageView.js.map +1 -0
  23. package/dist/PopoverMenu.d.ts +103 -0
  24. package/dist/PopoverMenu.d.ts.map +1 -0
  25. package/dist/PopoverMenu.js +312 -0
  26. package/dist/PopoverMenu.js.map +1 -0
  27. package/dist/SmartSelect.d.ts +99 -0
  28. package/dist/SmartSelect.d.ts.map +1 -0
  29. package/dist/SmartSelect.js.map +1 -1
  30. package/dist/Toast.d.ts +127 -0
  31. package/dist/Toast.d.ts.map +1 -0
  32. package/dist/Toast.js +507 -0
  33. package/dist/Toast.js.map +1 -0
  34. package/dist/TreeView.d.ts +84 -0
  35. package/dist/TreeView.d.ts.map +1 -0
  36. package/dist/TreeView.js +478 -0
  37. package/dist/TreeView.js.map +1 -0
  38. package/dist/index.d.ts +16 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +30 -6
  41. package/dist/index.js.map +1 -1
  42. package/package.json +43 -3
  43. package/src/ChunkUploader.ts +921 -0
  44. package/src/ContainerBox.ts +570 -0
  45. package/src/DateSelector.ts +550 -0
  46. package/src/Drawer.ts +435 -0
  47. package/src/ImageView.ts +265 -0
  48. package/src/PopoverMenu.ts +595 -0
  49. package/src/SmartSelect.ts +231 -231
  50. package/src/Toast.ts +834 -0
  51. package/src/TreeView.ts +673 -0
  52. package/src/index.ts +70 -3
@@ -0,0 +1,614 @@
1
+ class v extends HTMLElement {
2
+ constructor() {
3
+ super(), this.files = /* @__PURE__ */ new Map(), this.config = {
4
+ serverURL: "",
5
+ chunkSize: 5,
6
+ maxFileSize: 5120
7
+ }, this.isUploading = !1, this.abortController = null, this.attachShadow({ mode: "open" }), this.render(), this.bindEvents();
8
+ }
9
+ static get observedAttributes() {
10
+ return ["server-url", "chunk-size", "auth-token", "valid-filetypes", "max-file-size"];
11
+ }
12
+ attributeChangedCallback(e, r, o) {
13
+ if (r !== o)
14
+ switch (e) {
15
+ case "server-url":
16
+ this.config.serverURL = o || "";
17
+ break;
18
+ case "chunk-size":
19
+ this.config.chunkSize = parseFloat(o || String(5));
20
+ break;
21
+ case "auth-token":
22
+ this.config.authToken = o || void 0;
23
+ break;
24
+ case "valid-filetypes":
25
+ this.config.validFiletypes = o ? o.split(",").map((t) => t.trim()) : void 0;
26
+ break;
27
+ case "max-file-size":
28
+ this.config.maxFileSize = parseFloat(o || String(5120));
29
+ break;
30
+ }
31
+ }
32
+ // Property getters and setters
33
+ get serverURL() {
34
+ return this.config.serverURL;
35
+ }
36
+ set serverURL(e) {
37
+ this.config.serverURL = e, this.setAttribute("server-url", e);
38
+ }
39
+ get chunkSize() {
40
+ return this.config.chunkSize;
41
+ }
42
+ set chunkSize(e) {
43
+ this.config.chunkSize = e, this.setAttribute("chunk-size", e.toString());
44
+ }
45
+ get authToken() {
46
+ return this.config.authToken;
47
+ }
48
+ set authToken(e) {
49
+ e ? (this.config.authToken = e, this.setAttribute("auth-token", e)) : (this.config.authToken = void 0, this.removeAttribute("auth-token"));
50
+ }
51
+ get validFiletypes() {
52
+ return this.config.validFiletypes;
53
+ }
54
+ set validFiletypes(e) {
55
+ this.config.validFiletypes = e, e ? this.setAttribute("valid-filetypes", e.join(",")) : this.removeAttribute("valid-filetypes");
56
+ }
57
+ get maxFileSize() {
58
+ return this.config.maxFileSize || 5120;
59
+ }
60
+ set maxFileSize(e) {
61
+ this.config.maxFileSize = e, this.setAttribute("max-file-size", e.toString());
62
+ }
63
+ set onfilecomplete(e) {
64
+ this.config.onfilecomplete = e;
65
+ }
66
+ set onuploadcomplete(e) {
67
+ this.config.onuploadcomplete = e;
68
+ }
69
+ /**
70
+ * Formats bytes to human readable string
71
+ */
72
+ formatBytes(e) {
73
+ if (e === 0) return "0 Bytes";
74
+ const r = 1024, o = ["Bytes", "KB", "MB", "GB"], t = Math.floor(Math.log(e) / Math.log(r));
75
+ return Math.round(e / Math.pow(r, t) * 100) / 100 + " " + o[t];
76
+ }
77
+ /**
78
+ * Generates a unique ID for a file
79
+ */
80
+ generateFileId() {
81
+ return `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
82
+ }
83
+ /**
84
+ * Validates a file based on config
85
+ */
86
+ validateFile(e) {
87
+ const r = this.maxFileSize * 1024 * 1024;
88
+ if (e.size > r)
89
+ return {
90
+ valid: !1,
91
+ error: `File size exceeds maximum of ${this.formatBytes(r)}`
92
+ };
93
+ if (this.config.validFiletypes && this.config.validFiletypes.length > 0) {
94
+ const o = e.name.split(".").pop()?.toLowerCase();
95
+ if (!o || !this.config.validFiletypes.includes(o))
96
+ return {
97
+ valid: !1,
98
+ error: `File type .${o} is not allowed. Valid types: ${this.config.validFiletypes.join(", ")}`
99
+ };
100
+ }
101
+ return { valid: !0 };
102
+ }
103
+ /**
104
+ * Generates a preview for image files
105
+ */
106
+ async generatePreview(e) {
107
+ if (e.type.startsWith("image/"))
108
+ return new Promise((r) => {
109
+ const o = new FileReader();
110
+ o.onload = (t) => r(t.target?.result), o.onerror = () => r(void 0), o.readAsDataURL(e);
111
+ });
112
+ }
113
+ /**
114
+ * Adds files to the upload queue
115
+ */
116
+ async addFiles(e) {
117
+ for (let r = 0; r < e.length; r++) {
118
+ const o = e[r], t = this.validateFile(o), i = this.generateFileId(), s = {
119
+ id: i,
120
+ file: o,
121
+ status: t.valid ? "pending" : "error",
122
+ progress: 0,
123
+ uploadedBytes: 0,
124
+ error: t.error
125
+ };
126
+ t.valid && o.type.startsWith("image/") && (s.preview = await this.generatePreview(o)), this.files.set(i, s);
127
+ }
128
+ this.renderFileCards();
129
+ }
130
+ /**
131
+ * Removes a file from the queue
132
+ */
133
+ removeFile(e) {
134
+ this.files.delete(e), this.renderFileCards();
135
+ }
136
+ /**
137
+ * Uploads a single file with chunking
138
+ */
139
+ async uploadFile(e) {
140
+ if (!this.config.serverURL)
141
+ throw new Error("Server URL is not configured");
142
+ const { file: r } = e;
143
+ e.status = "uploading", e.progress = 0, this.updateFileCard(e.id);
144
+ try {
145
+ const o = {
146
+ "Content-Type": "application/json"
147
+ };
148
+ this.config.authToken && (o.Authorization = `Bearer ${this.config.authToken}`);
149
+ const t = await fetch(`${this.config.serverURL}/api/upload/initiate`, {
150
+ method: "POST",
151
+ headers: o,
152
+ body: JSON.stringify({
153
+ fileName: r.name,
154
+ fileType: r.type
155
+ })
156
+ });
157
+ if (!t.ok)
158
+ throw new Error(`Failed to initiate upload: ${await t.text()}`);
159
+ const { uploadId: i, key: s } = await t.json();
160
+ e.uploadId = i, e.key = s;
161
+ const n = this.config.chunkSize * 1024 * 1024, f = Math.ceil(r.size / n), d = [];
162
+ for (let a = 1; a <= f; a++) {
163
+ if (this.abortController?.signal.aborted)
164
+ throw new Error("Upload aborted by user");
165
+ const c = (a - 1) * n, p = Math.min(c + n, r.size), g = r.slice(c, p), h = {
166
+ "Content-Type": "application/octet-stream",
167
+ "X-Upload-Id": i,
168
+ "X-Key": s,
169
+ "X-Part-Number": a.toString()
170
+ };
171
+ this.config.authToken && (h.Authorization = `Bearer ${this.config.authToken}`);
172
+ const u = await fetch(`${this.config.serverURL}/api/upload/part`, {
173
+ method: "POST",
174
+ headers: h,
175
+ body: g,
176
+ signal: this.abortController?.signal
177
+ });
178
+ if (!u.ok)
179
+ throw new Error(`Failed to upload part ${a}`);
180
+ const { etag: b } = await u.json();
181
+ d.push({ partNumber: a, etag: b }), e.uploadedBytes = p, e.progress = e.uploadedBytes / r.size * 100, this.updateFileCard(e.id);
182
+ }
183
+ if (!(await fetch(`${this.config.serverURL}/api/upload/complete`, {
184
+ method: "POST",
185
+ headers: o,
186
+ body: JSON.stringify({
187
+ uploadId: i,
188
+ key: s,
189
+ parts: d
190
+ })
191
+ })).ok)
192
+ throw new Error("Failed to complete upload");
193
+ e.status = "completed", e.progress = 100, this.updateFileCard(e.id), this.dispatchEvent(new CustomEvent("filecomplete", {
194
+ detail: e,
195
+ bubbles: !0,
196
+ composed: !0
197
+ })), this.config.onfilecomplete && this.config.onfilecomplete(e);
198
+ } catch (o) {
199
+ throw o instanceof Error && (o.name === "AbortError" || o.message === "Upload aborted by user") || (e.status = "error", e.error = o instanceof Error ? o.message : "Unknown error", this.updateFileCard(e.id)), o;
200
+ }
201
+ }
202
+ /**
203
+ * Starts uploading all pending files
204
+ */
205
+ async startUpload() {
206
+ if (this.isUploading) return;
207
+ const e = Array.from(this.files.values()).filter((t) => t.status === "pending");
208
+ if (e.length === 0) return;
209
+ this.isUploading = !0, this.abortController = new AbortController();
210
+ const r = this.shadowRoot.querySelector("#uploadBtn"), o = this.shadowRoot.querySelector("#abortBtn");
211
+ r && (r.disabled = !0, r.textContent = "Uploading..."), o && (o.style.display = "inline-block");
212
+ try {
213
+ for (const t of e) {
214
+ if (this.abortController.signal.aborted)
215
+ break;
216
+ await this.uploadFile(t);
217
+ }
218
+ this.dispatchEvent(new CustomEvent("uploadcomplete", {
219
+ detail: Array.from(this.files.values()),
220
+ bubbles: !0,
221
+ composed: !0
222
+ })), this.config.onuploadcomplete && this.config.onuploadcomplete(Array.from(this.files.values()));
223
+ } catch (t) {
224
+ t instanceof Error && t.message !== "Upload aborted by user" && console.error("Upload error:", t);
225
+ } finally {
226
+ this.isUploading = !1, r && (r.disabled = !1, r.textContent = "Upload Files"), o && (o.style.display = "none");
227
+ }
228
+ }
229
+ /**
230
+ * Aborts all pending and uploading files
231
+ */
232
+ async abortAllUploads() {
233
+ this.abortController && this.abortController.abort();
234
+ const e = Array.from(this.files.values()).filter(
235
+ (i) => i.status === "pending" || i.status === "uploading"
236
+ );
237
+ if (e.length === 0) return;
238
+ const r = {
239
+ "Content-Type": "application/json"
240
+ };
241
+ this.config.authToken && (r.Authorization = `Bearer ${this.config.authToken}`);
242
+ for (const i of e) {
243
+ if (i.uploadId && i.key)
244
+ try {
245
+ await fetch(`${this.config.serverURL}/api/upload/abort`, {
246
+ method: "POST",
247
+ headers: r,
248
+ body: JSON.stringify({
249
+ uploadId: i.uploadId,
250
+ key: i.key
251
+ })
252
+ });
253
+ } catch (s) {
254
+ console.error(`Failed to abort upload for ${i.file.name}:`, s);
255
+ }
256
+ i.status = "aborted", i.error = "Upload aborted by user", this.updateFileCard(i.id);
257
+ }
258
+ this.dispatchEvent(new CustomEvent("uploadaborted", {
259
+ detail: e,
260
+ bubbles: !0,
261
+ composed: !0
262
+ })), this.isUploading = !1;
263
+ const o = this.shadowRoot.querySelector("#uploadBtn"), t = this.shadowRoot.querySelector("#abortBtn");
264
+ o && (o.disabled = !1, o.textContent = "Upload Files"), t && (t.style.display = "none");
265
+ }
266
+ /**
267
+ * Updates a single file card in the DOM
268
+ */
269
+ updateFileCard(e) {
270
+ const r = this.files.get(e);
271
+ if (!r) return;
272
+ const o = this.shadowRoot.querySelector(`[data-file-id="${e}"]`);
273
+ if (!o) return;
274
+ const t = o.querySelector(".progress-bar"), i = o.querySelector(".progress-text"), s = o.querySelector(".status");
275
+ t && (t.style.width = `${r.progress}%`, r.status === "completed" ? t.style.backgroundColor = "#22c55e" : r.status === "error" ? t.style.backgroundColor = "#ef4444" : r.status === "aborted" ? t.style.backgroundColor = "#f59e0b" : t.style.backgroundColor = "var(--color-primary)"), i && (i.textContent = `${Math.round(r.progress)}%`), s && r.error && (s.textContent = r.error, s.style.display = "block");
276
+ }
277
+ /**
278
+ * Renders all file cards
279
+ */
280
+ renderFileCards() {
281
+ const e = this.shadowRoot.querySelector("#fileCardsContainer");
282
+ if (!e) return;
283
+ if (this.files.size === 0) {
284
+ e.innerHTML = "";
285
+ return;
286
+ }
287
+ e.innerHTML = Array.from(this.files.values()).map((t) => `
288
+ <div class="file-card" data-file-id="${t.id}">
289
+ <button class="remove-btn" data-file-id="${t.id}">×</button>
290
+ ${t.preview ? `<div class="preview"><img src="${t.preview}" alt="Preview"></div>` : '<div class="preview no-preview">📄</div>'}
291
+ <div class="file-info">
292
+ <div class="file-name" title="${t.file.name}">${t.file.name}</div>
293
+ <div class="file-size">${this.formatBytes(t.file.size)}</div>
294
+ </div>
295
+ <div class="progress-container">
296
+ <div class="progress-bar-bg">
297
+ <div class="progress-bar" style="width: ${t.progress}%; background-color: ${t.status === "completed" ? "#22c55e" : t.status === "error" ? "#ef4444" : "var(--color-primary)"}"></div>
298
+ </div>
299
+ <div class="progress-text">${Math.round(t.progress)}%</div>
300
+ </div>
301
+ ${t.error ? `<div class="status error">${t.error}</div>` : ""}
302
+ </div>
303
+ `).join(""), e.querySelectorAll(".remove-btn").forEach((t) => {
304
+ t.addEventListener("click", (i) => {
305
+ i.stopPropagation();
306
+ const s = t.dataset.fileId;
307
+ s && this.removeFile(s);
308
+ });
309
+ });
310
+ const o = this.shadowRoot.querySelector("#uploadBtn");
311
+ if (o) {
312
+ const t = Array.from(this.files.values()).some((i) => i.status === "pending");
313
+ o.style.display = t ? "block" : "none";
314
+ }
315
+ }
316
+ /**
317
+ * Binds event listeners
318
+ */
319
+ bindEvents() {
320
+ const e = this.shadowRoot.querySelector("#uploadZone"), r = this.shadowRoot.querySelector("#fileInput"), o = this.shadowRoot.querySelector("#browseBtn"), t = this.shadowRoot.querySelector("#uploadBtn"), i = this.shadowRoot.querySelector("#abortBtn");
321
+ o?.addEventListener("click", () => r?.click()), e?.addEventListener("dragover", (s) => {
322
+ s.preventDefault(), e.classList.add("drag-over");
323
+ }), e?.addEventListener("dragleave", () => {
324
+ e.classList.remove("drag-over");
325
+ }), e?.addEventListener("drop", (s) => {
326
+ s.preventDefault(), e.classList.remove("drag-over"), s.dataTransfer?.files && this.addFiles(s.dataTransfer.files);
327
+ }), r?.addEventListener("change", (s) => {
328
+ const n = s.target.files;
329
+ n && (this.addFiles(n), r.value = "");
330
+ }), t?.addEventListener("click", () => this.startUpload()), i?.addEventListener("click", () => this.abortAllUploads());
331
+ }
332
+ /**
333
+ * Renders the component
334
+ */
335
+ render() {
336
+ this.shadowRoot.innerHTML = `
337
+ <style>
338
+ :host {
339
+ display: block;
340
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
341
+ }
342
+
343
+ * {
344
+ box-sizing: border-box;
345
+ }
346
+
347
+ .container {
348
+ width: 100%;
349
+ }
350
+
351
+ .upload-zone {
352
+ border: 2px dashed #ccc;
353
+ border-radius: 8px;
354
+ padding: 40px;
355
+ text-align: center;
356
+ cursor: pointer;
357
+ transition: all 0.3s ease;
358
+ background: #fafafa;
359
+ }
360
+
361
+ .upload-zone:hover {
362
+ border-color: #4CAF50;
363
+ background: #f0f9f0;
364
+ }
365
+
366
+ .upload-zone.drag-over {
367
+ border-color: #4CAF50;
368
+ background: #e8f5e9;
369
+ }
370
+
371
+ .upload-zone-content {
372
+ pointer-events: none;
373
+ }
374
+
375
+ .upload-icon {
376
+ font-size: 48px;
377
+ margin-bottom: 16px;
378
+ }
379
+
380
+ .upload-text {
381
+ font-size: 18px;
382
+ margin-bottom: 8px;
383
+ color: #333;
384
+ }
385
+
386
+ .upload-hint {
387
+ font-size: 14px;
388
+ color: #666;
389
+ }
390
+
391
+ .browse-btn {
392
+ background: #4CAF50;
393
+ color: white;
394
+ border: none;
395
+ padding: 12px 24px;
396
+ border-radius: 6px;
397
+ font-size: 16px;
398
+ font-weight: 500;
399
+ cursor: pointer;
400
+ margin-top: 16px;
401
+ transition: background 0.3s ease;
402
+ pointer-events: auto;
403
+ }
404
+
405
+ .browse-btn:hover {
406
+ background: #45a049;
407
+ }
408
+
409
+ input[type="file"] {
410
+ display: none;
411
+ }
412
+
413
+ .file-cards-container {
414
+ display: flex;
415
+ flex-wrap: wrap;
416
+ gap: 16px;
417
+ margin-top: 24px;
418
+ }
419
+
420
+ .file-card {
421
+ position: relative;
422
+ width: 200px;
423
+ border: 1px solid #e0e0e0;
424
+ border-radius: 8px;
425
+ padding: 12px;
426
+ background: white;
427
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
428
+ transition: box-shadow 0.3s ease;
429
+ }
430
+
431
+ .file-card:hover {
432
+ box-shadow: 0 4px 8px rgba(0,0,0,0.15);
433
+ }
434
+
435
+ .remove-btn {
436
+ position: absolute;
437
+ top: 8px;
438
+ right: 8px;
439
+ width: 24px;
440
+ height: 24px;
441
+ border: none;
442
+ border-radius: 50%;
443
+ background: rgba(239, 68, 68, 0.9);
444
+ color: white;
445
+ font-size: 18px;
446
+ line-height: 1;
447
+ cursor: pointer;
448
+ display: flex;
449
+ align-items: center;
450
+ justify-content: center;
451
+ padding: 0;
452
+ transition: background 0.3s ease;
453
+ z-index: 1;
454
+ }
455
+
456
+ .remove-btn:hover {
457
+ background: rgba(239, 68, 68, 1);
458
+ }
459
+
460
+ .preview {
461
+ width: 100%;
462
+ height: 120px;
463
+ border-radius: 4px;
464
+ overflow: hidden;
465
+ background: #f5f5f5;
466
+ display: flex;
467
+ align-items: center;
468
+ justify-content: center;
469
+ margin-bottom: 8px;
470
+ }
471
+
472
+ .preview img {
473
+ width: 100%;
474
+ height: 100%;
475
+ object-fit: cover;
476
+ }
477
+
478
+ .preview.no-preview {
479
+ font-size: 48px;
480
+ }
481
+
482
+ .file-info {
483
+ margin-bottom: 8px;
484
+ }
485
+
486
+ .file-name {
487
+ font-size: 14px;
488
+ font-weight: 500;
489
+ color: #333;
490
+ white-space: nowrap;
491
+ overflow: hidden;
492
+ text-overflow: ellipsis;
493
+ margin-bottom: 4px;
494
+ }
495
+
496
+ .file-size {
497
+ font-size: 12px;
498
+ color: #666;
499
+ }
500
+
501
+ .progress-container {
502
+ margin-top: 8px;
503
+ }
504
+
505
+ .progress-bar-bg {
506
+ width: 100%;
507
+ height: 8px;
508
+ background: #e0e0e0;
509
+ border-radius: 4px;
510
+ overflow: hidden;
511
+ margin-bottom: 4px;
512
+ }
513
+
514
+ .progress-bar {
515
+ height: 100%;
516
+ background: var(--color-primary, #4CAF50);
517
+ transition: width 0.3s ease, background-color 0.3s ease;
518
+ }
519
+
520
+ .progress-text {
521
+ font-size: 12px;
522
+ color: #666;
523
+ text-align: center;
524
+ }
525
+
526
+ .status {
527
+ font-size: 12px;
528
+ color: #ef4444;
529
+ margin-top: 4px;
530
+ display: none;
531
+ }
532
+
533
+ .status.error {
534
+ display: block;
535
+ }
536
+
537
+ .upload-btn {
538
+ background: #4CAF50;
539
+ color: white;
540
+ border: none;
541
+ padding: 12px 32px;
542
+ border-radius: 6px;
543
+ font-size: 16px;
544
+ font-weight: 500;
545
+ cursor: pointer;
546
+ margin-top: 24px;
547
+ transition: background 0.3s ease;
548
+ display: none;
549
+ }
550
+
551
+ .upload-btn:hover:not(:disabled) {
552
+ background: #45a049;
553
+ }
554
+
555
+ .upload-btn:disabled {
556
+ opacity: 0.6;
557
+ cursor: not-allowed;
558
+ }
559
+
560
+ .abort-btn {
561
+ background: #ef4444;
562
+ color: white;
563
+ border: none;
564
+ padding: 12px 32px;
565
+ border-radius: 6px;
566
+ font-size: 16px;
567
+ font-weight: 500;
568
+ cursor: pointer;
569
+ margin-top: 24px;
570
+ margin-left: 12px;
571
+ transition: background 0.3s ease;
572
+ display: none;
573
+ }
574
+
575
+ .abort-btn:hover {
576
+ background: #dc2626;
577
+ }
578
+
579
+ .buttons-container {
580
+ display: flex;
581
+ align-items: center;
582
+ }
583
+ </style>
584
+
585
+ <div class="container">
586
+ <div class="upload-zone" id="uploadZone">
587
+ <input type="file" id="fileInput" multiple>
588
+ <div class="upload-zone-content">
589
+ <div class="upload-icon">📁</div>
590
+ <div class="upload-text">Drop files here</div>
591
+ <div class="upload-hint">or</div>
592
+ <button class="browse-btn" id="browseBtn">Browse Files</button>
593
+ </div>
594
+ </div>
595
+
596
+ <div class="file-cards-container" id="fileCardsContainer"></div>
597
+
598
+ <div class="buttons-container">
599
+ <button class="upload-btn" id="uploadBtn">Upload Files</button>
600
+ <button class="abort-btn" id="abortBtn">Abort Upload</button>
601
+ </div>
602
+ </div>
603
+ `;
604
+ }
605
+ }
606
+ const m = (l = "liwe3-chunk-uploader") => {
607
+ typeof window < "u" && !customElements.get(l) && customElements.define(l, v);
608
+ };
609
+ typeof window < "u" && m();
610
+ export {
611
+ v as ChunkUploaderElement,
612
+ m as defineChunkUploader
613
+ };
614
+ //# sourceMappingURL=ChunkUploader.js.map