@liwe3/webcomponents 1.0.14 → 1.1.10

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