@singlebase/elements 0.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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/authui.cjs +2 -0
  4. package/dist/authui.cjs.map +1 -0
  5. package/dist/authui.d.ts +22 -0
  6. package/dist/authui.js +24 -0
  7. package/dist/authui.js.map +1 -0
  8. package/dist/controllers/auth-controller.d.ts +17 -0
  9. package/dist/controllers/event-bridge.d.ts +27 -0
  10. package/dist/controllers/settings-controller.d.ts +18 -0
  11. package/dist/display-8HEcKYR4.js +3444 -0
  12. package/dist/display-8HEcKYR4.js.map +1 -0
  13. package/dist/display-CLDNNZQy.cjs +976 -0
  14. package/dist/display-CLDNNZQy.cjs.map +1 -0
  15. package/dist/elements/account-screen.d.ts +99 -0
  16. package/dist/elements/auth-screen.d.ts +215 -0
  17. package/dist/elements/base.d.ts +69 -0
  18. package/dist/elements/buttons.d.ts +45 -0
  19. package/dist/elements/display.d.ts +51 -0
  20. package/dist/elements/form-base.d.ts +23 -0
  21. package/dist/elements/guard.d.ts +65 -0
  22. package/dist/elements/uploader.d.ts +225 -0
  23. package/dist/index.cjs +2 -0
  24. package/dist/index.cjs.map +1 -0
  25. package/dist/index.d.ts +7 -0
  26. package/dist/index.js +30 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/messages.d.ts +147 -0
  29. package/dist/singlebase-elements.min.js +7616 -0
  30. package/dist/singlebase-elements.min.js.map +1 -0
  31. package/dist/standalone.d.ts +2 -0
  32. package/dist/styles/shared.d.ts +8 -0
  33. package/dist/styles/tokens.d.ts +44 -0
  34. package/dist/upload-messages.d.ts +45 -0
  35. package/dist/uploader-D-Da1trc.js +2290 -0
  36. package/dist/uploader-D-Da1trc.js.map +1 -0
  37. package/dist/uploader-eFYKpk8b.cjs +1390 -0
  38. package/dist/uploader-eFYKpk8b.cjs.map +1 -0
  39. package/dist/uploader.cjs +2 -0
  40. package/dist/uploader.cjs.map +1 -0
  41. package/dist/uploader.d.ts +10 -0
  42. package/dist/uploader.js +9 -0
  43. package/dist/uploader.js.map +1 -0
  44. package/dist/utils/files.d.ts +38 -0
  45. package/dist/utils/inspect.d.ts +23 -0
  46. package/dist/utils/profile.d.ts +9 -0
  47. package/dist/utils/redirect.d.ts +15 -0
  48. package/package.json +76 -0
@@ -0,0 +1,2290 @@
1
+ var ue = (r) => {
2
+ throw TypeError(r);
3
+ };
4
+ var be = (r, e, t) => e.has(r) || ue("Cannot " + t);
5
+ var d = (r, e, t) => (be(r, e, "read from private field"), t ? t.call(r) : e.get(r)), l = (r, e, t) => e.has(r) ? ue("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t), c = (r, e, t, o) => (be(r, e, "write to private field"), o ? o.call(r, t) : e.set(r, t), t);
6
+ import { unsafeCSS as ge, css as se, LitElement as Ce, nothing as x, html as f } from "lit";
7
+ import { property as g, state as Z, customElement as Me } from "lit/decorators.js";
8
+ import { getDefaultClient as Le } from "@singlebase/core";
9
+ const he = {
10
+ font: '"Geist", -apple-system, "Segoe UI", Helvetica, sans-serif',
11
+ mono: '"Geist Mono", ui-monospace, monospace',
12
+ accent: "#111111",
13
+ onAccent: "#ffffff",
14
+ radius: "4px",
15
+ surface: "#ffffff",
16
+ surfaceAlt: "#fafafa",
17
+ ink: "#16181a",
18
+ mutedInk: "#61666c",
19
+ border: "#e4e6e9",
20
+ borderStrong: "#cdd1d6",
21
+ danger: "#b4231a",
22
+ dangerBg: "#fdf1f0",
23
+ dangerBorder: "#f3d6d3",
24
+ dangerOutline: "#e8c4c0",
25
+ dangerPanelBorder: "#efd9d6",
26
+ dangerPanelBg: "#fdf7f6",
27
+ ok: "#0f6b4a",
28
+ okBg: "#f0f7f3",
29
+ okBorder: "#cfe5da",
30
+ gap: "16px",
31
+ pad: "20px",
32
+ fieldPad: "11px 13px"
33
+ }, Te = se`
34
+ :host {
35
+ display: block;
36
+ box-sizing: border-box;
37
+ font-family: var(--sb-font, ${ge(he.font)});
38
+ color: var(--sb-ink, ${ge(he.ink)});
39
+ }
40
+
41
+ :host([theme="dark"]) {
42
+ /* The light default accent is near-black, which disappears on a dark
43
+ surface — primary buttons and links both use it. A host that sets its
44
+ own --sb-accent still wins: outer-page declarations beat :host rules. */
45
+ --sb-accent: #f3f4f5;
46
+ --sb-on-accent: #17181b;
47
+ --sb-surface: #17181b;
48
+ --sb-surface-alt: #202226;
49
+ --sb-ink: #f3f4f5;
50
+ --sb-muted-ink: #a2a8ae;
51
+ --sb-border: #2c2f34;
52
+ --sb-border-strong: #3a3e44;
53
+ --sb-danger: #f08379;
54
+ --sb-danger-bg: rgba(240, 131, 121, 0.1);
55
+ --sb-danger-border: rgba(240, 131, 121, 0.3);
56
+ --sb-danger-outline: rgba(240, 131, 121, 0.4);
57
+ --sb-danger-panel-border: rgba(240, 131, 121, 0.3);
58
+ --sb-danger-panel-bg: rgba(240, 131, 121, 0.06);
59
+ --sb-ok: #6fd1a6;
60
+ --sb-ok-bg: rgba(111, 209, 166, 0.1);
61
+ --sb-ok-border: rgba(111, 209, 166, 0.28);
62
+ }
63
+
64
+ :host([density="compact"]) {
65
+ --sb-gap: 12px;
66
+ --sb-pad: 16px;
67
+ --sb-field-pad: 9px 11px;
68
+ }
69
+ `, Fe = se`
70
+ /* ── layout primitives ───────────────────────────────────── */
71
+ .stack {
72
+ display: flex;
73
+ flex-direction: column;
74
+ gap: var(--sb-gap, 16px);
75
+ }
76
+
77
+ .fields {
78
+ display: flex;
79
+ flex-direction: column;
80
+ gap: var(--sb-gap, 16px);
81
+ }
82
+
83
+ .head {
84
+ display: flex;
85
+ flex-direction: column;
86
+ gap: 6px;
87
+ }
88
+
89
+ .two-up {
90
+ display: grid;
91
+ grid-template-columns: 1fr 1fr;
92
+ gap: var(--sb-gap, 16px);
93
+ }
94
+
95
+ .actions {
96
+ display: flex;
97
+ flex-direction: column;
98
+ gap: 8px;
99
+ }
100
+
101
+ .rule {
102
+ height: 1px;
103
+ background: var(--sb-border, #e4e6e9);
104
+ }
105
+
106
+ .between {
107
+ display: flex;
108
+ align-items: flex-start;
109
+ justify-content: space-between;
110
+ gap: 16px;
111
+ }
112
+
113
+ /* ── type ────────────────────────────────────────────────── */
114
+ .logo-dot {
115
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
116
+ font-size: 12px;
117
+ letter-spacing: 0.08em;
118
+ text-transform: uppercase;
119
+ color: var(--sb-muted-ink, #61666c);
120
+ margin-bottom: 6px;
121
+ }
122
+
123
+ .title {
124
+ margin: 0;
125
+ font-size: 20px;
126
+ font-weight: 600;
127
+ letter-spacing: -0.015em;
128
+ color: var(--sb-ink, #16181a);
129
+ }
130
+
131
+ .sub {
132
+ margin: 0;
133
+ font-size: 13.5px;
134
+ line-height: 1.5;
135
+ color: var(--sb-muted-ink, #61666c);
136
+ text-wrap: pretty;
137
+ }
138
+
139
+ .sec-title {
140
+ margin: 0;
141
+ font-size: 14px;
142
+ font-weight: 600;
143
+ letter-spacing: -0.01em;
144
+ color: var(--sb-ink, #16181a);
145
+ }
146
+
147
+ .hint {
148
+ margin: 0;
149
+ font-size: 12.5px;
150
+ line-height: 1.5;
151
+ color: var(--sb-muted-ink, #61666c);
152
+ text-wrap: pretty;
153
+ }
154
+
155
+ .sub-label {
156
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
157
+ font-size: 11px;
158
+ letter-spacing: 0.07em;
159
+ text-transform: uppercase;
160
+ color: var(--sb-muted-ink, #61666c);
161
+ }
162
+
163
+ /* ── fields ──────────────────────────────────────────────── */
164
+ .field {
165
+ display: flex;
166
+ flex-direction: column;
167
+ gap: 6px;
168
+ }
169
+
170
+ .label-row {
171
+ display: flex;
172
+ align-items: baseline;
173
+ justify-content: space-between;
174
+ gap: 8px;
175
+ }
176
+
177
+ label,
178
+ .label {
179
+ font-size: 12.5px;
180
+ font-weight: 500;
181
+ color: var(--sb-muted-ink, #61666c);
182
+ letter-spacing: 0.01em;
183
+ }
184
+
185
+ input {
186
+ width: 100%;
187
+ box-sizing: border-box;
188
+ font: inherit;
189
+ font-size: 14px;
190
+ color: var(--sb-ink, #16181a);
191
+ background: var(--sb-surface-alt, #fafafa);
192
+ border: 1px solid var(--sb-border, #e4e6e9);
193
+ border-radius: var(--sb-radius, 4px);
194
+ padding: var(--sb-field-pad, 11px 13px);
195
+ outline: none;
196
+ }
197
+
198
+ input:focus {
199
+ border-color: var(--sb-accent, #111111);
200
+ }
201
+
202
+ input[aria-invalid="true"] {
203
+ border-color: var(--sb-danger, #b4231a);
204
+ }
205
+
206
+ /* field-style="underline" — code boxes keep their box, they read as cells */
207
+ :host([field-style="underline"]) *:not(.code-row):not(.code-row-sm) > input {
208
+ background: transparent;
209
+ border: none;
210
+ border-bottom: 1px solid var(--sb-border-strong, #cdd1d6);
211
+ border-radius: 0;
212
+ padding: 9px 2px;
213
+ }
214
+
215
+ p.err {
216
+ margin: 0;
217
+ font-size: 12.5px;
218
+ color: var(--sb-danger, #b4231a);
219
+ }
220
+
221
+ /* ── code entry ──────────────────────────────────────────── */
222
+ .code-row {
223
+ display: grid;
224
+ grid-template-columns: repeat(6, 1fr);
225
+ gap: 8px;
226
+ }
227
+
228
+ .code-row input {
229
+ text-align: center;
230
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
231
+ font-size: 18px;
232
+ padding: 12px 0;
233
+ }
234
+
235
+ .code-row-sm {
236
+ display: grid;
237
+ grid-template-columns: repeat(6, 1fr);
238
+ gap: 6px;
239
+ }
240
+
241
+ .code-row-sm input {
242
+ text-align: center;
243
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
244
+ font-size: 14px;
245
+ padding: 8px 0;
246
+ }
247
+
248
+ .resend-row {
249
+ display: flex;
250
+ align-items: baseline;
251
+ gap: 8px;
252
+ }
253
+
254
+ /* ── buttons ─────────────────────────────────────────────── */
255
+ button {
256
+ display: inline-flex;
257
+ align-items: center;
258
+ justify-content: center;
259
+ gap: 8px;
260
+ font: inherit;
261
+ font-size: 13.5px;
262
+ font-weight: 500;
263
+ border-radius: var(--sb-radius, 4px);
264
+ cursor: pointer;
265
+ padding: 9px 14px;
266
+ border: 1px solid transparent;
267
+ transition:
268
+ background 0.15s,
269
+ border-color 0.15s,
270
+ filter 0.15s,
271
+ color 0.15s;
272
+ }
273
+
274
+ button:disabled {
275
+ cursor: not-allowed;
276
+ }
277
+
278
+ button.primary {
279
+ background: var(--sb-accent, #111111);
280
+ color: var(--sb-on-accent, #ffffff);
281
+ width: 100%;
282
+ }
283
+
284
+ button.primary:hover:not(:disabled) {
285
+ filter: brightness(0.92);
286
+ }
287
+
288
+ button.primary-sm {
289
+ background: var(--sb-accent, #111111);
290
+ color: var(--sb-on-accent, #ffffff);
291
+ padding: 7px 12px;
292
+ }
293
+
294
+ button.primary-sm:hover:not(:disabled) {
295
+ filter: brightness(0.92);
296
+ }
297
+
298
+ button.ghost {
299
+ background: transparent;
300
+ color: var(--sb-muted-ink, #61666c);
301
+ border: 1px solid var(--sb-border, #e4e6e9);
302
+ width: 100%;
303
+ }
304
+
305
+ button.ghost-sm {
306
+ background: transparent;
307
+ color: var(--sb-muted-ink, #61666c);
308
+ border: 1px solid var(--sb-border, #e4e6e9);
309
+ padding: 7px 12px;
310
+ }
311
+
312
+ button.ghost:hover:not(:disabled),
313
+ button.ghost-sm:hover:not(:disabled) {
314
+ background: var(--sb-surface-alt, #fafafa);
315
+ color: var(--sb-ink, #16181a);
316
+ }
317
+
318
+ button.secondary {
319
+ background: var(--sb-surface, #ffffff);
320
+ color: var(--sb-ink, #16181a);
321
+ border: 1px solid var(--sb-border-strong, #cdd1d6);
322
+ padding: 7px 12px;
323
+ }
324
+
325
+ button.secondary:hover:not(:disabled) {
326
+ background: var(--sb-surface-alt, #fafafa);
327
+ }
328
+
329
+ button.link {
330
+ font: inherit;
331
+ font-size: 13px;
332
+ font-weight: 500;
333
+ color: var(--sb-accent, #111111);
334
+ background: none;
335
+ border: none;
336
+ padding: 0;
337
+ cursor: pointer;
338
+ text-decoration: underline;
339
+ text-underline-offset: 3px;
340
+ }
341
+
342
+ button.link-sm {
343
+ font: inherit;
344
+ font-size: 12.5px;
345
+ font-weight: 400;
346
+ color: var(--sb-muted-ink, #61666c);
347
+ background: none;
348
+ border: none;
349
+ padding: 0;
350
+ cursor: pointer;
351
+ text-decoration: underline;
352
+ text-underline-offset: 3px;
353
+ }
354
+
355
+ /* the mock's editLink: a muted underlined affordance that inks on hover */
356
+ button.edit-link {
357
+ align-self: flex-start;
358
+ font: inherit;
359
+ font-size: 12.5px;
360
+ font-weight: 400;
361
+ color: var(--sb-muted-ink, #61666c);
362
+ background: none;
363
+ border: none;
364
+ padding: 0;
365
+ cursor: pointer;
366
+ text-decoration: underline;
367
+ text-underline-offset: 3px;
368
+ transition: color 0.15s;
369
+ }
370
+
371
+ button.edit-link:hover:not(:disabled) {
372
+ color: var(--sb-ink, #16181a);
373
+ }
374
+
375
+ button.edit-link:disabled {
376
+ opacity: 0.4;
377
+ }
378
+
379
+ button.danger-link {
380
+ align-self: flex-start;
381
+ font: inherit;
382
+ font-size: 12.5px;
383
+ font-weight: 400;
384
+ color: var(--sb-muted-ink, #61666c);
385
+ background: none;
386
+ border: none;
387
+ padding: 0;
388
+ cursor: pointer;
389
+ text-decoration: underline;
390
+ text-underline-offset: 3px;
391
+ transition: color 0.15s;
392
+ }
393
+
394
+ button.danger-link:hover:not(:disabled) {
395
+ color: var(--sb-danger, #b4231a);
396
+ }
397
+
398
+ button.danger {
399
+ padding: 7px 12px;
400
+ background: transparent;
401
+ color: var(--sb-danger, #b4231a);
402
+ border: 1px solid var(--sb-danger-outline, #e8c4c0);
403
+ }
404
+
405
+ button.danger:hover:not(:disabled) {
406
+ background: var(--sb-danger-bg, #fdf1f0);
407
+ }
408
+
409
+ button.danger:disabled {
410
+ opacity: 0.45;
411
+ }
412
+
413
+ .btn-row {
414
+ display: flex;
415
+ align-items: center;
416
+ gap: 8px;
417
+ flex-wrap: wrap;
418
+ }
419
+
420
+ .btn-row-end {
421
+ display: flex;
422
+ align-items: center;
423
+ justify-content: flex-end;
424
+ gap: 12px;
425
+ flex-wrap: wrap;
426
+ }
427
+
428
+ .edit-actions {
429
+ display: flex;
430
+ gap: 8px;
431
+ padding-top: 2px;
432
+ }
433
+
434
+ /* ── feedback ────────────────────────────────────────────── */
435
+ .banner,
436
+ .notice {
437
+ font-size: 13px;
438
+ line-height: 1.45;
439
+ border-radius: var(--sb-radius, 4px);
440
+ padding: 10px 12px;
441
+ }
442
+
443
+ .banner {
444
+ color: var(--sb-danger, #b4231a);
445
+ background: var(--sb-danger-bg, #fdf1f0);
446
+ border: 1px solid var(--sb-danger-border, #f3d6d3);
447
+ }
448
+
449
+ .notice {
450
+ color: var(--sb-ok, #0f6b4a);
451
+ background: var(--sb-ok-bg, #f0f7f3);
452
+ border: 1px solid var(--sb-ok-border, #cfe5da);
453
+ }
454
+
455
+ .saved-note {
456
+ font-size: 12.5px;
457
+ font-weight: 500;
458
+ color: var(--sb-ok, #0f6b4a);
459
+ }
460
+
461
+ .spinner {
462
+ width: 13px;
463
+ height: 13px;
464
+ border: 2px solid rgba(255, 255, 255, 0.4);
465
+ border-top-color: var(--sb-on-accent, #ffffff);
466
+ border-radius: 50%;
467
+ animation: sb-spin 0.7s linear infinite;
468
+ }
469
+
470
+ @keyframes sb-spin {
471
+ to {
472
+ transform: rotate(360deg);
473
+ }
474
+ }
475
+
476
+ .sr-only {
477
+ position: absolute;
478
+ width: 1px;
479
+ height: 1px;
480
+ overflow: hidden;
481
+ clip: rect(0 0 0 0);
482
+ white-space: nowrap;
483
+ }
484
+
485
+ /* ── step bar ────────────────────────────────────────────── */
486
+ .step-bar {
487
+ height: 3px;
488
+ background: var(--sb-border, #e4e6e9);
489
+ border-radius: 99px;
490
+ overflow: hidden;
491
+ }
492
+
493
+ .step-fill {
494
+ height: 100%;
495
+ background: var(--sb-accent, #111111);
496
+ transition: width 0.3s;
497
+ }
498
+
499
+ /* ── footer link row ─────────────────────────────────────── */
500
+ .foot {
501
+ margin: 0;
502
+ display: flex;
503
+ gap: 6px;
504
+ justify-content: center;
505
+ font-size: 13px;
506
+ color: var(--sb-muted-ink, #61666c);
507
+ }
508
+
509
+ /* ── oauth ───────────────────────────────────────────────── */
510
+ .oauth-primary {
511
+ background: var(--sb-surface, #ffffff);
512
+ color: var(--sb-ink, #16181a);
513
+ border: 1px solid var(--sb-border-strong, #cdd1d6);
514
+ width: 100%;
515
+ }
516
+
517
+ .oauth-primary:hover:not(:disabled) {
518
+ background: var(--sb-surface-alt, #fafafa);
519
+ }
520
+
521
+ .g-mark {
522
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
523
+ font-weight: 500;
524
+ font-size: 13px;
525
+ color: var(--sb-muted-ink, #61666c);
526
+ }
527
+
528
+ .icon-row {
529
+ display: grid;
530
+ grid-template-columns: repeat(3, 1fr);
531
+ gap: 8px;
532
+ }
533
+
534
+ .icon-btn {
535
+ padding: 7px 0;
536
+ background: var(--sb-surface, #ffffff);
537
+ color: var(--sb-muted-ink, #61666c);
538
+ border: 1px solid var(--sb-border, #e4e6e9);
539
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
540
+ font-size: 13px;
541
+ }
542
+
543
+ .icon-btn:hover:not(:disabled) {
544
+ background: var(--sb-surface-alt, #fafafa);
545
+ color: var(--sb-ink, #16181a);
546
+ }
547
+
548
+ /* ── accordion (method picker) ───────────────────────────── */
549
+ .acc-wrap {
550
+ display: flex;
551
+ flex-direction: column;
552
+ gap: 8px;
553
+ }
554
+
555
+ .acc-item {
556
+ border: 1px solid var(--sb-border, #e4e6e9);
557
+ border-radius: var(--sb-radius, 4px);
558
+ overflow: hidden;
559
+ background: transparent;
560
+ transition:
561
+ border-color 0.2s,
562
+ background 0.2s;
563
+ }
564
+
565
+ .acc-item.open {
566
+ border-color: var(--sb-border-strong, #cdd1d6);
567
+ background: var(--sb-surface, #ffffff);
568
+ }
569
+
570
+ .acc-item.bare {
571
+ border: none;
572
+ background: transparent;
573
+ }
574
+
575
+ .acc-head {
576
+ display: flex;
577
+ align-items: center;
578
+ gap: 10px;
579
+ width: 100%;
580
+ box-sizing: border-box;
581
+ font: inherit;
582
+ text-align: left;
583
+ background: transparent;
584
+ border: none;
585
+ border-radius: 0;
586
+ padding: 11px 12px;
587
+ cursor: pointer;
588
+ color: var(--sb-ink, #16181a);
589
+ transition: background 0.15s;
590
+ }
591
+
592
+ .acc-head:hover {
593
+ background: var(--sb-surface-alt, #fafafa);
594
+ }
595
+
596
+ .chev {
597
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
598
+ font-size: 13px;
599
+ color: var(--sb-muted-ink, #61666c);
600
+ line-height: 1;
601
+ transform: rotate(0deg);
602
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
603
+ }
604
+
605
+ .acc-item.open .chev {
606
+ transform: rotate(90deg);
607
+ }
608
+
609
+ .acc-title {
610
+ font-size: 13.5px;
611
+ font-weight: 500;
612
+ color: var(--sb-ink, #16181a);
613
+ letter-spacing: -0.005em;
614
+ }
615
+
616
+ .acc-meta {
617
+ font-size: 12px;
618
+ color: var(--sb-muted-ink, #61666c);
619
+ margin-left: auto;
620
+ overflow: hidden;
621
+ text-overflow: ellipsis;
622
+ white-space: nowrap;
623
+ }
624
+
625
+ .acc-body {
626
+ display: grid;
627
+ grid-template-rows: 0fr;
628
+ opacity: 0;
629
+ transition:
630
+ grid-template-rows 0.28s cubic-bezier(0.32, 0.72, 0, 1),
631
+ opacity 0.16s ease;
632
+ }
633
+
634
+ .acc-item.open .acc-body {
635
+ grid-template-rows: 1fr;
636
+ opacity: 1;
637
+ transition:
638
+ grid-template-rows 0.34s cubic-bezier(0.32, 0.72, 0, 1),
639
+ opacity 0.26s ease 0.06s;
640
+ }
641
+
642
+ .acc-clip {
643
+ overflow: hidden;
644
+ min-height: 0;
645
+ }
646
+
647
+ .acc-inner {
648
+ display: flex;
649
+ flex-direction: column;
650
+ gap: var(--sb-gap, 16px);
651
+ padding: 2px 12px 14px;
652
+ transform: translateY(-4px);
653
+ transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
654
+ }
655
+
656
+ .acc-item.open .acc-inner {
657
+ transform: translateY(0);
658
+ }
659
+
660
+ .acc-item.bare .acc-inner {
661
+ padding: 0;
662
+ }
663
+
664
+ /* ── invite ──────────────────────────────────────────────── */
665
+ .invite-box {
666
+ display: flex;
667
+ flex-direction: column;
668
+ gap: 2px;
669
+ padding: 10px 12px;
670
+ background: var(--sb-surface-alt, #fafafa);
671
+ border: 1px solid var(--sb-border, #e4e6e9);
672
+ border-radius: var(--sb-radius, 4px);
673
+ }
674
+
675
+ .invite-label {
676
+ font-size: 11.5px;
677
+ letter-spacing: 0.04em;
678
+ text-transform: uppercase;
679
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
680
+ color: var(--sb-muted-ink, #61666c);
681
+ }
682
+
683
+ .invite-email {
684
+ font-size: 14px;
685
+ color: var(--sb-ink, #16181a);
686
+ }
687
+
688
+ /* ── account ─────────────────────────────────────────────── */
689
+ .acct-root {
690
+ display: flex;
691
+ flex-direction: column;
692
+ gap: 22px;
693
+ width: 100%;
694
+ }
695
+
696
+ .acct-nav {
697
+ display: flex;
698
+ align-items: flex-start;
699
+ justify-content: space-between;
700
+ gap: 16px;
701
+ padding-bottom: 18px;
702
+ border-bottom: 1px solid var(--sb-border, #e4e6e9);
703
+ }
704
+
705
+ .acct-who {
706
+ display: flex;
707
+ align-items: center;
708
+ gap: 10px;
709
+ }
710
+
711
+ .avatar-col {
712
+ flex: 0 0 auto;
713
+ display: flex;
714
+ flex-direction: column;
715
+ align-items: center;
716
+ gap: 6px;
717
+ }
718
+
719
+ .avatar {
720
+ flex: 0 0 auto;
721
+ width: 42px;
722
+ height: 42px;
723
+ border-radius: 50%;
724
+ background: var(--sb-surface-alt, #fafafa);
725
+ border: 1px dashed var(--sb-border, #e4e6e9);
726
+ display: flex;
727
+ align-items: center;
728
+ justify-content: center;
729
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
730
+ font-size: 13px;
731
+ color: var(--sb-muted-ink, #61666c);
732
+ }
733
+
734
+ .avatar.has-photo {
735
+ border-style: solid;
736
+ overflow: hidden;
737
+ }
738
+ .avatar img {
739
+ width: 100%;
740
+ height: 100%;
741
+ object-fit: cover;
742
+ }
743
+
744
+ .avatar-lg {
745
+ width: 56px;
746
+ height: 56px;
747
+ border-radius: 50%;
748
+ background: var(--sb-surface-alt, #fafafa);
749
+ border: 1px dashed var(--sb-border-strong, #cdd1d6);
750
+ display: flex;
751
+ align-items: center;
752
+ justify-content: center;
753
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
754
+ font-size: 13px;
755
+ color: var(--sb-muted-ink, #61666c);
756
+ }
757
+
758
+ .avatar-row {
759
+ display: flex;
760
+ align-items: center;
761
+ gap: 14px;
762
+ }
763
+
764
+ .avatar-actions {
765
+ display: flex;
766
+ flex-direction: column;
767
+ gap: 6px;
768
+ }
769
+
770
+ .acct-who-text {
771
+ min-width: 0;
772
+ }
773
+
774
+ .acct-name {
775
+ font-size: 14px;
776
+ font-weight: 600;
777
+ color: var(--sb-ink, #16181a);
778
+ letter-spacing: -0.01em;
779
+ }
780
+
781
+ .acct-email {
782
+ font-size: 12.5px;
783
+ color: var(--sb-muted-ink, #61666c);
784
+ overflow: hidden;
785
+ text-overflow: ellipsis;
786
+ white-space: nowrap;
787
+ }
788
+
789
+ .acct-body {
790
+ flex: 1;
791
+ min-width: 0;
792
+ display: flex;
793
+ flex-direction: column;
794
+ gap: 22px;
795
+ }
796
+
797
+ .section {
798
+ display: flex;
799
+ flex-direction: column;
800
+ gap: 14px;
801
+ }
802
+
803
+ .sum-list {
804
+ display: flex;
805
+ flex-direction: column;
806
+ }
807
+
808
+ .sum-row {
809
+ display: flex;
810
+ align-items: baseline;
811
+ justify-content: space-between;
812
+ gap: 16px;
813
+ padding: 15px 0;
814
+ border-bottom: 1px solid var(--sb-border, #e4e6e9);
815
+ }
816
+
817
+ .sum-label {
818
+ flex: 0 0 auto;
819
+ font-size: 12.5px;
820
+ color: var(--sb-muted-ink, #61666c);
821
+ }
822
+
823
+ .sum-value {
824
+ min-width: 0;
825
+ font-size: 13.5px;
826
+ color: var(--sb-ink, #16181a);
827
+ overflow: hidden;
828
+ text-overflow: ellipsis;
829
+ white-space: nowrap;
830
+ }
831
+
832
+ .edit-card {
833
+ display: flex;
834
+ flex-direction: column;
835
+ gap: var(--sb-gap, 16px);
836
+ padding: 14px;
837
+ background: var(--sb-surface-alt, #fafafa);
838
+ border: 1px solid var(--sb-border, #e4e6e9);
839
+ border-radius: var(--sb-radius, 4px);
840
+ }
841
+
842
+ /* 2FA switch */
843
+ .switch {
844
+ flex: 0 0 auto;
845
+ width: 42px;
846
+ height: 24px;
847
+ border-radius: 99px;
848
+ border: 1px solid var(--sb-border-strong, #cdd1d6);
849
+ background: var(--sb-surface-alt, #fafafa);
850
+ cursor: pointer;
851
+ padding: 2px;
852
+ display: flex;
853
+ justify-content: flex-start;
854
+ align-items: center;
855
+ transition:
856
+ background 0.15s,
857
+ border-color 0.15s;
858
+ }
859
+
860
+ .switch[aria-pressed="true"] {
861
+ border-color: var(--sb-accent, #111111);
862
+ background: var(--sb-accent, #111111);
863
+ justify-content: flex-end;
864
+ }
865
+
866
+ .knob {
867
+ width: 18px;
868
+ height: 18px;
869
+ border-radius: 50%;
870
+ background: var(--sb-muted-ink, #61666c);
871
+ display: block;
872
+ }
873
+
874
+ .switch[aria-pressed="true"] .knob {
875
+ background: var(--sb-on-accent, #ffffff);
876
+ }
877
+
878
+ .qr-row {
879
+ display: flex;
880
+ gap: 14px;
881
+ align-items: flex-start;
882
+ }
883
+
884
+ .qr-box {
885
+ flex: 0 0 auto;
886
+ width: 74px;
887
+ height: 74px;
888
+ border-radius: var(--sb-radius, 4px);
889
+ background: var(--sb-surface-alt, #fafafa);
890
+ border: 1px dashed var(--sb-border-strong, #cdd1d6);
891
+ display: flex;
892
+ align-items: center;
893
+ justify-content: center;
894
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
895
+ font-size: 12px;
896
+ color: var(--sb-muted-ink, #61666c);
897
+ }
898
+
899
+ .qr-text {
900
+ display: flex;
901
+ flex-direction: column;
902
+ gap: 10px;
903
+ min-width: 0;
904
+ }
905
+
906
+ /* connected accounts */
907
+ .list {
908
+ display: flex;
909
+ flex-direction: column;
910
+ gap: 8px;
911
+ }
912
+
913
+ .conn-row {
914
+ display: flex;
915
+ align-items: center;
916
+ justify-content: space-between;
917
+ gap: 12px;
918
+ padding: 10px 12px;
919
+ border: 1px solid var(--sb-border, #e4e6e9);
920
+ border-radius: var(--sb-radius, 4px);
921
+ background: var(--sb-surface-alt, #fafafa);
922
+ }
923
+
924
+ .conn-left {
925
+ display: flex;
926
+ align-items: center;
927
+ gap: 10px;
928
+ min-width: 0;
929
+ }
930
+
931
+ .conn-mark {
932
+ flex: 0 0 auto;
933
+ width: 28px;
934
+ height: 28px;
935
+ border-radius: 50%;
936
+ background: var(--sb-surface, #ffffff);
937
+ border: 1px solid var(--sb-border, #e4e6e9);
938
+ display: flex;
939
+ align-items: center;
940
+ justify-content: center;
941
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
942
+ font-size: 11px;
943
+ color: var(--sb-muted-ink, #61666c);
944
+ }
945
+
946
+ .conn-name {
947
+ font-size: 13.5px;
948
+ font-weight: 500;
949
+ color: var(--sb-ink, #16181a);
950
+ }
951
+
952
+ .meta-row {
953
+ display: flex;
954
+ align-items: center;
955
+ gap: 6px;
956
+ }
957
+
958
+ .dot {
959
+ flex: 0 0 auto;
960
+ width: 5px;
961
+ height: 5px;
962
+ border-radius: 50%;
963
+ background: var(--sb-ok, #0f6b4a);
964
+ }
965
+
966
+ .conn-meta {
967
+ font-size: 12px;
968
+ color: var(--sb-muted-ink, #61666c);
969
+ }
970
+
971
+ .tile-grid {
972
+ display: grid;
973
+ grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
974
+ gap: 8px;
975
+ }
976
+
977
+ .tile {
978
+ display: flex;
979
+ align-items: center;
980
+ gap: 8px;
981
+ font: inherit;
982
+ text-align: left;
983
+ padding: 10px 11px;
984
+ border-radius: var(--sb-radius, 4px);
985
+ border: 1px dashed var(--sb-border-strong, #cdd1d6);
986
+ background: transparent;
987
+ cursor: pointer;
988
+ transition:
989
+ background 0.15s,
990
+ border-color 0.15s,
991
+ color 0.15s;
992
+ }
993
+
994
+ .tile:hover:not(:disabled) {
995
+ background: var(--sb-surface-alt, #fafafa);
996
+ border-color: var(--sb-accent, #111111);
997
+ border-style: solid;
998
+ }
999
+
1000
+ .tile-mark {
1001
+ flex: 0 0 auto;
1002
+ width: 22px;
1003
+ height: 22px;
1004
+ border-radius: 50%;
1005
+ background: var(--sb-surface-alt, #fafafa);
1006
+ display: flex;
1007
+ align-items: center;
1008
+ justify-content: center;
1009
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
1010
+ font-size: 10.5px;
1011
+ color: var(--sb-muted-ink, #61666c);
1012
+ }
1013
+
1014
+ .tile-name {
1015
+ font-size: 13px;
1016
+ color: var(--sb-ink, #16181a);
1017
+ overflow: hidden;
1018
+ text-overflow: ellipsis;
1019
+ white-space: nowrap;
1020
+ }
1021
+
1022
+ .tile-plus {
1023
+ margin-left: auto;
1024
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
1025
+ font-size: 14px;
1026
+ line-height: 1;
1027
+ color: var(--sb-muted-ink, #61666c);
1028
+ }
1029
+
1030
+ .delete-panel {
1031
+ display: flex;
1032
+ flex-direction: column;
1033
+ gap: 12px;
1034
+ padding: 14px;
1035
+ border: 1px solid var(--sb-danger-panel-border, #efd9d6);
1036
+ border-radius: var(--sb-radius, 4px);
1037
+ background: var(--sb-danger-panel-bg, #fdf7f6);
1038
+ }
1039
+
1040
+ .disabled-note {
1041
+ font-size: 12px;
1042
+ color: var(--sb-muted-ink, #61666c);
1043
+ font-style: italic;
1044
+ }
1045
+ `;
1046
+ function Oe(r, e, t) {
1047
+ if (!r || !e) return null;
1048
+ let o;
1049
+ try {
1050
+ o = new URL(e);
1051
+ } catch {
1052
+ return null;
1053
+ }
1054
+ let n;
1055
+ try {
1056
+ n = new URL(r, o.href);
1057
+ } catch {
1058
+ return t == null || t(`"${r}" is not a valid URL`), null;
1059
+ }
1060
+ return n.protocol !== "http:" && n.protocol !== "https:" ? (t == null || t(`refusing redirect to unsupported scheme "${n.protocol}"`), null) : n.origin !== o.origin ? (t == null || t(`refusing cross-origin redirect to ${n.origin}; same-origin only`), null) : n.href === o.href ? null : n.href;
1061
+ }
1062
+ const me = {
1063
+ heading: "Upload files",
1064
+ description: "Add one or more files. You can review the list before uploading.",
1065
+ dropTitle: "Drag and drop files here",
1066
+ dropSub: "or browse from your device",
1067
+ hintUpTo: "up to {size} each",
1068
+ chooseFiles: "Choose files",
1069
+ chooseFile: "Choose file",
1070
+ addMore: "+ Add more files",
1071
+ remove: "Remove",
1072
+ rename: "Rename",
1073
+ retry: "Retry",
1074
+ uploadCtaOne: "Upload {n} file",
1075
+ uploadCtaMany: "Upload {n} files",
1076
+ attachments: "Attachments",
1077
+ dropOrChoose: "Drop files or choose",
1078
+ checking: "Checking…",
1079
+ pagesLabel: "{n} pages",
1080
+ countOne: "{n} file of {max}",
1081
+ countMany: "{n} files of {max}",
1082
+ uploading: "Uploading…",
1083
+ uploaded: "Uploaded",
1084
+ failedLabel: "Failed",
1085
+ errTooMany: "You can upload up to {max} files.",
1086
+ errTooLarge: "{name} is larger than {size}.",
1087
+ errTooSmall: "{name} is smaller than {size}.",
1088
+ errDuplicate: "{name} is already in the list.",
1089
+ errType: "{name} isn't an accepted file type.",
1090
+ errNoClient: "No Singlebase client found on this page.",
1091
+ errUpload: "Upload failed.",
1092
+ errProtected: "{name} is password protected.",
1093
+ errTooManyPages: "{name} has {pages} pages; the limit is {max}.",
1094
+ brandingLabel: "Files by Singlebase"
1095
+ };
1096
+ function De(r) {
1097
+ return r ? { ...me, ...r } : me;
1098
+ }
1099
+ function v(r, e) {
1100
+ return r.replace(
1101
+ /\{(\w+)\}/g,
1102
+ (t, o) => o in e ? String(e[o]) : t
1103
+ );
1104
+ }
1105
+ const je = {
1106
+ b: 1,
1107
+ kb: 1024,
1108
+ mb: 1024 * 1024,
1109
+ gb: 1024 * 1024 * 1024
1110
+ };
1111
+ function ne(r) {
1112
+ if (typeof r == "number") return r > 0 ? r : 0;
1113
+ if (!r) return 0;
1114
+ const e = String(r).trim().toLowerCase().match(/^([\d.]+)\s*(b|kb|mb|gb)?$/);
1115
+ if (!e) return 0;
1116
+ const t = Number.parseFloat(e[1]);
1117
+ return !Number.isFinite(t) || t <= 0 ? 0 : Math.round(t * (je[e[2] ?? "b"] ?? 1));
1118
+ }
1119
+ function ee(r) {
1120
+ return r < 1024 ? `${r} B` : r < 1024 * 1024 ? `${Math.round(r / 1024)} KB` : r < 1024 * 1024 * 1024 ? `${(r / (1024 * 1024)).toFixed(1)} MB` : `${(r / (1024 * 1024 * 1024)).toFixed(1)} GB`;
1121
+ }
1122
+ function te(r) {
1123
+ const e = r.lastIndexOf(".");
1124
+ return e <= 0 || e === r.length - 1 ? "" : r.slice(e + 1).toLowerCase();
1125
+ }
1126
+ function Ae(r) {
1127
+ return te(r).toUpperCase().slice(0, 4);
1128
+ }
1129
+ function Ee(r, e, t) {
1130
+ const o = r.split(",").map((i) => i.trim().toLowerCase()).filter(Boolean);
1131
+ if (!o.length) return !0;
1132
+ const n = e.toLowerCase(), u = (t || "").toLowerCase();
1133
+ return o.some((i) => i.startsWith(".") ? n.endsWith(i) : i.endsWith("/*") ? u.startsWith(i.slice(0, -1)) : u === i);
1134
+ }
1135
+ function Ne(r) {
1136
+ const e = r.split(",").map((t) => t.trim()).filter(Boolean).map((t) => {
1137
+ if (t.startsWith(".")) return t.slice(1).toUpperCase();
1138
+ if (t.endsWith("/*")) return t.slice(0, -2).toUpperCase();
1139
+ const o = t.indexOf("/");
1140
+ return (o >= 0 ? t.slice(o + 1) : t).toUpperCase();
1141
+ });
1142
+ return [...new Set(e)].join(", ");
1143
+ }
1144
+ function Be(r) {
1145
+ return `${r.name}:${r.size}:${r.lastModified ?? 0}`;
1146
+ }
1147
+ function Pe(r, e) {
1148
+ const t = e.trim().replace(/[/\\]/g, "");
1149
+ if (!t) return r;
1150
+ const o = r.lastIndexOf("."), n = o > 0 ? r.slice(o) : "";
1151
+ return n ? t.toLowerCase().endsWith(n.toLowerCase()) ? t : t + n : t;
1152
+ }
1153
+ const we = { pages: null, encrypted: null }, xe = 16 * 1024 * 1024, Re = 2 * 1024 * 1024, Ie = 40, Ge = 4 * 1024 * 1024, ke = /* @__PURE__ */ new Set(["docx", "pptx", "xlsx"]);
1154
+ async function _e(r, e) {
1155
+ try {
1156
+ if (e === "pdf") return await We(r);
1157
+ if (ke.has(e)) return await qe(r, e);
1158
+ } catch {
1159
+ }
1160
+ return we;
1161
+ }
1162
+ function Ke(r) {
1163
+ return r === "pdf" || ke.has(r);
1164
+ }
1165
+ async function We(r) {
1166
+ const e = await re(r.slice(0, xe)), t = r.size > xe ? await re(r.slice(Math.max(0, r.size - Re))) : null, o = oe(e) + (t ? oe(t) : ""), n = /\/Encrypt[\s/<>\]]/.test(o);
1167
+ let u = ze(o);
1168
+ return u === null && (u = await Ye(e)), { pages: u, encrypted: n };
1169
+ }
1170
+ function ze(r) {
1171
+ if (/\/Type\s*\/Pages/.test(r)) {
1172
+ let t = 0;
1173
+ for (const o of r.matchAll(/\/Count\s+(\d+)/g))
1174
+ t = Math.max(t, Number(o[1]));
1175
+ if (t > 0) return t;
1176
+ }
1177
+ const e = r.match(/\/Type\s*\/Page[^s]/g);
1178
+ return e != null && e.length ? e.length : null;
1179
+ }
1180
+ async function Ye(r) {
1181
+ if (typeof DecompressionStream > "u") return null;
1182
+ const e = oe(r);
1183
+ let t = "", o = 0;
1184
+ for (const n of e.matchAll(/stream\r?\n/g)) {
1185
+ if (o >= Ie || t.length >= Ge) break;
1186
+ const u = n.index + n[0].length;
1187
+ let i = e.indexOf("endstream", u);
1188
+ if (i < 0) break;
1189
+ for (; i > u && (e[i - 1] === `
1190
+ ` || e[i - 1] === "\r"); ) i -= 1;
1191
+ o += 1;
1192
+ try {
1193
+ const a = await $e(r.subarray(u, i), "deflate");
1194
+ t += oe(a);
1195
+ } catch {
1196
+ }
1197
+ }
1198
+ return t ? ze(t) : null;
1199
+ }
1200
+ async function qe(r, e) {
1201
+ const t = await re(r.slice(0, 8));
1202
+ if (He(t)) return { pages: null, encrypted: !0 };
1203
+ if (t[0] !== 80 || t[1] !== 75) return we;
1204
+ const o = await Ve(r, "docProps/app.xml");
1205
+ if (!o) return { pages: null, encrypted: !1 };
1206
+ const n = e === "pptx" ? "Slides" : "Pages", u = new TextDecoder().decode(o).match(new RegExp(`<${n}>(\\d+)</${n}>`));
1207
+ return { pages: u ? Number(u[1]) : null, encrypted: !1 };
1208
+ }
1209
+ function He(r) {
1210
+ return [208, 207, 17, 224, 161, 177, 26, 225].every((t, o) => r[o] === t);
1211
+ }
1212
+ async function Ve(r, e) {
1213
+ const t = Math.min(r.size, 66e3), o = new DataView(await r.slice(r.size - t).arrayBuffer());
1214
+ let n = -1;
1215
+ for (let h = o.byteLength - 22; h >= 0; h--)
1216
+ if (o.getUint32(h, !0) === 101010256) {
1217
+ n = h;
1218
+ break;
1219
+ }
1220
+ if (n < 0) return null;
1221
+ const u = o.getUint32(n + 12, !0), i = o.getUint32(n + 16, !0);
1222
+ if (!u || i === 4294967295) return null;
1223
+ const a = new DataView(await r.slice(i, i + u).arrayBuffer()), m = new TextDecoder();
1224
+ let b = 0;
1225
+ for (; b + 46 <= a.byteLength && a.getUint32(b, !0) === 33639248; ) {
1226
+ const h = a.getUint16(b + 10, !0), Q = a.getUint32(b + 20, !0), y = a.getUint16(b + 28, !0), ie = a.getUint16(b + 30, !0), Se = a.getUint16(b + 32, !0), ae = a.getUint32(b + 42, !0);
1227
+ if (m.decode(new Uint8Array(a.buffer, a.byteOffset + b + 46, y)) === e) {
1228
+ const ce = new DataView(await r.slice(ae, ae + 30).arrayBuffer()), pe = ae + 30 + ce.getUint16(26, !0) + ce.getUint16(28, !0), fe = await re(r.slice(pe, pe + Q));
1229
+ return h === 0 ? fe : h === 8 && typeof DecompressionStream < "u" ? await $e(fe, "deflate-raw") : null;
1230
+ }
1231
+ b += 46 + y + ie + Se;
1232
+ }
1233
+ return null;
1234
+ }
1235
+ async function re(r) {
1236
+ return new Uint8Array(await r.arrayBuffer());
1237
+ }
1238
+ async function $e(r, e) {
1239
+ const t = new Blob([r]).stream().pipeThrough(new DecompressionStream(e));
1240
+ return new Uint8Array(await new Response(t).arrayBuffer());
1241
+ }
1242
+ function oe(r) {
1243
+ let e = "";
1244
+ for (let o = 0; o < r.length; o += 32768)
1245
+ e += String.fromCharCode(...r.subarray(o, o + 32768));
1246
+ return e;
1247
+ }
1248
+ var Ue = Object.defineProperty, Je = Object.getOwnPropertyDescriptor, Xe = (r, e, t) => e in r ? Ue(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, p = (r, e, t, o) => {
1249
+ for (var n = o > 1 ? void 0 : o ? Je(e, t) : e, u = r.length - 1, i; u >= 0; u--)
1250
+ (i = r[u]) && (n = (o ? i(e, t, n) : i(n)) || n);
1251
+ return o && n && Ue(e, t, n), n;
1252
+ }, Ze = (r, e, t) => Xe(r, e + "", t);
1253
+ const de = {
1254
+ fromAttribute: (r) => {
1255
+ if (!r) return {};
1256
+ try {
1257
+ const e = JSON.parse(r);
1258
+ return e && typeof e == "object" ? e : {};
1259
+ } catch {
1260
+ return console.warn("[singlebase-uploader] an attribute holds invalid JSON; ignoring it"), {};
1261
+ }
1262
+ },
1263
+ toAttribute: (r) => JSON.stringify(r ?? {})
1264
+ }, le = {
1265
+ fromAttribute: (r) => r === null ? !0 : r !== "false",
1266
+ toAttribute: (r) => r ? null : "false"
1267
+ }, ve = [
1268
+ "view",
1269
+ "dropzone",
1270
+ "allowRename",
1271
+ "autoUpload",
1272
+ "branding",
1273
+ "logoUrl",
1274
+ "logoText",
1275
+ "heading",
1276
+ "description",
1277
+ "maxFiles",
1278
+ "maxSize",
1279
+ "minSize",
1280
+ "accept",
1281
+ "rules",
1282
+ "bucket",
1283
+ "publicRead",
1284
+ "redirectUrl",
1285
+ "metadata",
1286
+ "options",
1287
+ "messages",
1288
+ "theme",
1289
+ "density",
1290
+ "onComplete",
1291
+ "onError"
1292
+ ];
1293
+ var k, z, $, U, S, C, M, L, T, F, O, D, j, A, E, N, B, P, R, I, G, _, K, W, Y, q, H, V, J, X, ye;
1294
+ let s = (ye = class extends Ce {
1295
+ constructor() {
1296
+ super(...arguments);
1297
+ l(this, k, null);
1298
+ l(this, z, {});
1299
+ l(this, $);
1300
+ l(this, U);
1301
+ l(this, S, "full");
1302
+ l(this, C, !0);
1303
+ l(this, M, !0);
1304
+ l(this, L, !1);
1305
+ l(this, T, !0);
1306
+ l(this, F, "");
1307
+ l(this, O, "");
1308
+ l(this, D, "");
1309
+ l(this, j, "");
1310
+ l(this, A, 10);
1311
+ l(this, E, "25MB");
1312
+ l(this, N, 0);
1313
+ l(this, B, "");
1314
+ l(this, P, {});
1315
+ l(this, R, "default");
1316
+ l(this, I, {});
1317
+ l(this, G, {});
1318
+ l(this, _, !1);
1319
+ l(this, K, "");
1320
+ l(this, W, null);
1321
+ l(this, Y, null);
1322
+ l(this, q, []);
1323
+ l(this, H, "");
1324
+ l(this, V, !1);
1325
+ l(this, J, !1);
1326
+ l(this, X, "");
1327
+ }
1328
+ get client() {
1329
+ return d(this, k);
1330
+ }
1331
+ set client(e) {
1332
+ c(this, k, e);
1333
+ }
1334
+ get messages() {
1335
+ return d(this, z);
1336
+ }
1337
+ set messages(e) {
1338
+ c(this, z, e);
1339
+ }
1340
+ get theme() {
1341
+ return d(this, $);
1342
+ }
1343
+ set theme(e) {
1344
+ c(this, $, e);
1345
+ }
1346
+ get density() {
1347
+ return d(this, U);
1348
+ }
1349
+ set density(e) {
1350
+ c(this, U, e);
1351
+ }
1352
+ get view() {
1353
+ return d(this, S);
1354
+ }
1355
+ set view(e) {
1356
+ c(this, S, e);
1357
+ }
1358
+ get dropzone() {
1359
+ return d(this, C);
1360
+ }
1361
+ set dropzone(e) {
1362
+ c(this, C, e);
1363
+ }
1364
+ get allowRename() {
1365
+ return d(this, M);
1366
+ }
1367
+ set allowRename(e) {
1368
+ c(this, M, e);
1369
+ }
1370
+ get autoUpload() {
1371
+ return d(this, L);
1372
+ }
1373
+ set autoUpload(e) {
1374
+ c(this, L, e);
1375
+ }
1376
+ get branding() {
1377
+ return d(this, T);
1378
+ }
1379
+ set branding(e) {
1380
+ c(this, T, e);
1381
+ }
1382
+ get logoUrl() {
1383
+ return d(this, F);
1384
+ }
1385
+ set logoUrl(e) {
1386
+ c(this, F, e);
1387
+ }
1388
+ get logoText() {
1389
+ return d(this, O);
1390
+ }
1391
+ set logoText(e) {
1392
+ c(this, O, e);
1393
+ }
1394
+ get heading() {
1395
+ return d(this, D);
1396
+ }
1397
+ set heading(e) {
1398
+ c(this, D, e);
1399
+ }
1400
+ get description() {
1401
+ return d(this, j);
1402
+ }
1403
+ set description(e) {
1404
+ c(this, j, e);
1405
+ }
1406
+ get maxFiles() {
1407
+ return d(this, A);
1408
+ }
1409
+ set maxFiles(e) {
1410
+ c(this, A, e);
1411
+ }
1412
+ get maxSize() {
1413
+ return d(this, E);
1414
+ }
1415
+ set maxSize(e) {
1416
+ c(this, E, e);
1417
+ }
1418
+ get minSize() {
1419
+ return d(this, N);
1420
+ }
1421
+ set minSize(e) {
1422
+ c(this, N, e);
1423
+ }
1424
+ get accept() {
1425
+ return d(this, B);
1426
+ }
1427
+ set accept(e) {
1428
+ c(this, B, e);
1429
+ }
1430
+ get rules() {
1431
+ return d(this, P);
1432
+ }
1433
+ set rules(e) {
1434
+ c(this, P, e);
1435
+ }
1436
+ get bucket() {
1437
+ return d(this, R);
1438
+ }
1439
+ set bucket(e) {
1440
+ c(this, R, e);
1441
+ }
1442
+ get metadata() {
1443
+ return d(this, I);
1444
+ }
1445
+ set metadata(e) {
1446
+ c(this, I, e);
1447
+ }
1448
+ get options() {
1449
+ return d(this, G);
1450
+ }
1451
+ set options(e) {
1452
+ c(this, G, e);
1453
+ }
1454
+ get publicRead() {
1455
+ return d(this, _);
1456
+ }
1457
+ set publicRead(e) {
1458
+ c(this, _, e);
1459
+ }
1460
+ get redirectUrl() {
1461
+ return d(this, K);
1462
+ }
1463
+ set redirectUrl(e) {
1464
+ c(this, K, e);
1465
+ }
1466
+ get onComplete() {
1467
+ return d(this, W);
1468
+ }
1469
+ set onComplete(e) {
1470
+ c(this, W, e);
1471
+ }
1472
+ get onError() {
1473
+ return d(this, Y);
1474
+ }
1475
+ set onError(e) {
1476
+ c(this, Y, e);
1477
+ }
1478
+ get items() {
1479
+ return d(this, q);
1480
+ }
1481
+ set items(e) {
1482
+ c(this, q, e);
1483
+ }
1484
+ get notice() {
1485
+ return d(this, H);
1486
+ }
1487
+ set notice(e) {
1488
+ c(this, H, e);
1489
+ }
1490
+ get busy() {
1491
+ return d(this, V);
1492
+ }
1493
+ set busy(e) {
1494
+ c(this, V, e);
1495
+ }
1496
+ get dragging() {
1497
+ return d(this, J);
1498
+ }
1499
+ set dragging(e) {
1500
+ c(this, J, e);
1501
+ }
1502
+ get editing() {
1503
+ return d(this, X);
1504
+ }
1505
+ set editing(e) {
1506
+ c(this, X, e);
1507
+ }
1508
+ get msg() {
1509
+ return De(this.messages);
1510
+ }
1511
+ /** An explicit `.client`, else the page default. */
1512
+ get resolvedClient() {
1513
+ return this.client ?? Le() ?? null;
1514
+ }
1515
+ /** The staging list, for host code that wants to inspect or persist it. */
1516
+ get files() {
1517
+ return this.items;
1518
+ }
1519
+ /** Overall progress across the current batch, 0–100. */
1520
+ get percent() {
1521
+ const e = this.items.filter((t) => t.status !== "ready");
1522
+ return e.length ? Math.round(e.reduce((t, o) => t + o.percent, 0) / e.length) : 0;
1523
+ }
1524
+ // ── public API ────────────────────────────────────────────
1525
+ /** Opens the file picker. */
1526
+ open() {
1527
+ var e;
1528
+ (e = this.renderRoot.querySelector("input[type=file]")) == null || e.click();
1529
+ }
1530
+ /**
1531
+ * Applies several settings at once:
1532
+ *
1533
+ * document.getElementById("docs").config = { maxFiles: 5, metadata: { folder: "q3" } };
1534
+ *
1535
+ * Unknown keys are ignored. Reading it returns the current settings.
1536
+ */
1537
+ set config(e) {
1538
+ const t = this;
1539
+ for (const o of ve)
1540
+ e && o in e && (t[o] = e[o]);
1541
+ }
1542
+ get config() {
1543
+ const e = this;
1544
+ return Object.fromEntries(ve.map((t) => [t, e[t]]));
1545
+ }
1546
+ /** Drops every staged file and any notice. */
1547
+ clear() {
1548
+ this.items.forEach(w), this.items = [], this.notice = "";
1549
+ }
1550
+ disconnectedCallback() {
1551
+ super.disconnectedCallback(), this.items.forEach(w);
1552
+ }
1553
+ /** Uploads everything staged. Rows that already succeeded are left alone. */
1554
+ async upload() {
1555
+ var u;
1556
+ if (this.busy) return;
1557
+ const e = this.items.filter((i) => i.status === "ready" || i.status === "error");
1558
+ if (!e.length) return;
1559
+ const t = this.resolvedClient;
1560
+ if (!t) {
1561
+ this.fail(this.msg.errNoClient);
1562
+ return;
1563
+ }
1564
+ this.busy = !0, this.notice = "";
1565
+ for (const i of e)
1566
+ i.status = "uploading", i.percent = 0, i.error = "";
1567
+ this.items = [...this.items];
1568
+ const o = /* @__PURE__ */ new Map(), n = e.map((i) => {
1569
+ const a = { file: i.file, filename: i.file.name };
1570
+ return this.bucket && (a.bucket = this.bucket), this.publicRead && (a.publicRead = !0), i.name !== i.file.name && (a.newName = i.name), Object.keys(this.metadata ?? {}).length && (a.metadata = { ...this.metadata }), Object.keys(this.options ?? {}).length && (a.options = { ...this.options }), o.set(a, i), a;
1571
+ });
1572
+ try {
1573
+ const i = await t.files.upload(n, {
1574
+ onProgress: (b) => {
1575
+ const h = o.get(b.input);
1576
+ h && (h.percent = b.percent, this.items = [...this.items], this.emit("singlebase-upload-progress", { file: h, percent: this.percent }));
1577
+ }
1578
+ });
1579
+ for (const b of i.completed) {
1580
+ const h = o.get(b.input);
1581
+ h && (h.status = "done", h.percent = 100, h.record = b.file);
1582
+ }
1583
+ for (const b of i.failed) {
1584
+ const h = o.get(b.input);
1585
+ h && (h.status = "error", h.error = b.error.message || b.error.code);
1586
+ }
1587
+ this.items = [...this.items];
1588
+ const a = i.completed.map((b) => o.get(b.input)).filter(Boolean), m = i.failed.map((b) => o.get(b.input)).filter(Boolean);
1589
+ this.emit("singlebase-upload-complete", { completed: a, failed: m }), (u = this.onComplete) == null || u.call(this, { completed: a, failed: m }), m.length ? this.notice = this.msg.errUpload : this.redirect();
1590
+ } catch (i) {
1591
+ for (const a of e)
1592
+ a.status = "error", a.error = "";
1593
+ this.items = [...this.items], this.fail(et(i) || this.msg.errUpload);
1594
+ } finally {
1595
+ this.busy = !1;
1596
+ }
1597
+ }
1598
+ // ── staging ───────────────────────────────────────────────
1599
+ /** The rule for this filename's extension, if the host set one. */
1600
+ ruleFor(e) {
1601
+ const t = te(e);
1602
+ if (!t) return null;
1603
+ for (const [o, n] of Object.entries(this.rules ?? {}))
1604
+ if (o.toLowerCase().replace(/^\./, "") === t) return n;
1605
+ return null;
1606
+ }
1607
+ async add(e) {
1608
+ if (this.view === "button") {
1609
+ const a = this.items.filter((m) => m.status === "done" || m.status === "error");
1610
+ a.forEach(w), this.items = this.items.filter((m) => !a.includes(m));
1611
+ }
1612
+ const t = this.maxFiles > 0 ? this.maxFiles : Number.POSITIVE_INFINITY, o = [...this.items], n = o.length, u = [];
1613
+ let i = "";
1614
+ for (const a of Array.from(e)) {
1615
+ if (o.length >= t) {
1616
+ i = v(this.msg.errTooMany, { max: t });
1617
+ break;
1618
+ }
1619
+ if (this.accept && !Ee(this.accept, a.name, a.type)) {
1620
+ i = v(this.msg.errType, { name: a.name });
1621
+ continue;
1622
+ }
1623
+ const m = this.ruleFor(a.name), b = ne((m == null ? void 0 : m.maxSize) ?? this.maxSize), h = ne((m == null ? void 0 : m.minSize) ?? this.minSize);
1624
+ if (b && a.size > b) {
1625
+ i = v(this.msg.errTooLarge, { name: a.name, size: ee(b) });
1626
+ continue;
1627
+ }
1628
+ if (h && a.size < h) {
1629
+ i = v(this.msg.errTooSmall, { name: a.name, size: ee(h) });
1630
+ continue;
1631
+ }
1632
+ const Q = Be(a);
1633
+ if (o.some((ie) => ie.key === Q)) {
1634
+ i = v(this.msg.errDuplicate, { name: a.name });
1635
+ continue;
1636
+ }
1637
+ const y = {
1638
+ key: Q,
1639
+ file: a,
1640
+ name: a.name,
1641
+ // Reading bytes takes a moment, so the row appears immediately as
1642
+ // "checking" rather than the widget freezing on a picked file.
1643
+ status: this.needsInspection(m, a.name) ? "checking" : "ready",
1644
+ percent: 0,
1645
+ error: "",
1646
+ record: null,
1647
+ pages: null,
1648
+ encrypted: null,
1649
+ preview: Qe(a)
1650
+ };
1651
+ o.push(y), u.push(y);
1652
+ }
1653
+ this.notice = i, i && this.emit("singlebase-upload-rejected", { message: i }), o.length !== n && (this.items = o, this.emit("singlebase-upload-selected", { files: this.items }), await Promise.all(
1654
+ u.filter((a) => a.status === "checking").map((a) => this.inspect(a, this.ruleFor(a.file.name)))
1655
+ ), (this.autoUpload || this.view === "button") && this.upload());
1656
+ }
1657
+ needsInspection(e, t) {
1658
+ return !e || !Ke(te(t)) ? !1 : e.maxPages !== void 0 || e.allowProtected === !1;
1659
+ }
1660
+ /**
1661
+ * Reads the file and applies the rule. A fact the reader could not
1662
+ * determine is not grounds for rejection — an unreadable page count means
1663
+ * the page rule simply doesn't apply to that file.
1664
+ */
1665
+ async inspect(e, t) {
1666
+ const o = await _e(e.file, te(e.file.name));
1667
+ e.pages = o.pages, e.encrypted = o.encrypted;
1668
+ let n = "";
1669
+ t.allowProtected === !1 && o.encrypted === !0 ? n = v(this.msg.errProtected, { name: e.name }) : t.maxPages && o.pages !== null && o.pages > t.maxPages && (n = v(this.msg.errTooManyPages, {
1670
+ name: e.name,
1671
+ pages: o.pages,
1672
+ max: t.maxPages
1673
+ })), n ? (w(e), this.items = this.items.filter((u) => u !== e), this.notice = n, this.emit("singlebase-upload-rejected", { message: n })) : (e.status = "ready", this.items = [...this.items]);
1674
+ }
1675
+ /** Drops one staged file. Named for the row action, not Element.remove(). */
1676
+ removeItem(e) {
1677
+ this.items.filter((t) => t.key === e).forEach(w), this.items = this.items.filter((t) => t.key !== e), this.notice = "";
1678
+ }
1679
+ commitRename(e, t) {
1680
+ e.name = Pe(e.file.name, t), this.editing = "", this.items = [...this.items];
1681
+ }
1682
+ fail(e) {
1683
+ var t;
1684
+ this.notice = e, this.emit("singlebase-upload-error", { message: e }), (t = this.onError) == null || t.call(this, { message: e });
1685
+ }
1686
+ emit(e, t) {
1687
+ this.dispatchEvent(new CustomEvent(e, { detail: t, bubbles: !0, composed: !0 }));
1688
+ }
1689
+ redirect() {
1690
+ if (!this.redirectUrl || typeof location > "u") return;
1691
+ const e = Oe(
1692
+ this.redirectUrl,
1693
+ location.href,
1694
+ (t) => console.warn(`[singlebase-uploader] ${t}`)
1695
+ );
1696
+ e && location.assign(e);
1697
+ }
1698
+ // ── events ────────────────────────────────────────────────
1699
+ onPick(e) {
1700
+ var o;
1701
+ const t = e.target;
1702
+ (o = t.files) != null && o.length && this.add(t.files), t.value = "";
1703
+ }
1704
+ onDrop(e) {
1705
+ var o;
1706
+ e.preventDefault(), this.dragging = !1;
1707
+ const t = (o = e.dataTransfer) == null ? void 0 : o.files;
1708
+ t != null && t.length && this.add(t);
1709
+ }
1710
+ onDragOver(e) {
1711
+ e.preventDefault(), this.dragging = !0;
1712
+ }
1713
+ onDragLeave() {
1714
+ this.dragging = !1;
1715
+ }
1716
+ // ── rendering ─────────────────────────────────────────────
1717
+ get canAddMore() {
1718
+ return this.maxFiles <= 0 || this.items.length < this.maxFiles;
1719
+ }
1720
+ /** True while any staged file is still being read. */
1721
+ get checking() {
1722
+ return this.items.some((e) => e.status === "checking");
1723
+ }
1724
+ get pendingCount() {
1725
+ return this.items.filter((e) => e.status === "ready" || e.status === "error").length;
1726
+ }
1727
+ get hint() {
1728
+ const e = Ne(this.accept), t = ne(this.maxSize), o = t ? v(this.msg.hintUpTo, { size: ee(t) }) : "";
1729
+ return [e, o].filter(Boolean).join(" · ");
1730
+ }
1731
+ renderInput() {
1732
+ return f`<input
1733
+ class="sr-only"
1734
+ type="file"
1735
+ ?multiple=${this.maxFiles !== 1}
1736
+ accept=${this.accept || x}
1737
+ @change=${this.onPick}
1738
+ />`;
1739
+ }
1740
+ renderLogo() {
1741
+ return this.logoUrl ? f`<img
1742
+ class="logo-img"
1743
+ src=${this.logoUrl}
1744
+ alt=${this.logoText || "Logo"}
1745
+ part="logo"
1746
+ />` : this.logoText ? f`<div class="brand-mark" part="logo">${this.logoText}</div>` : x;
1747
+ }
1748
+ renderBranding() {
1749
+ return this.branding ? f`<div class="branding" part="branding">
1750
+ <a href="https://singlebase.cloud" target="_blank" rel="noopener noreferrer"
1751
+ >${this.msg.brandingLabel}</a
1752
+ >
1753
+ </div>` : x;
1754
+ }
1755
+ renderNotice() {
1756
+ return this.notice ? f`<div class="banner" role="alert" part="error">${this.notice}</div>` : x;
1757
+ }
1758
+ renderCount() {
1759
+ if (!this.items.length) return x;
1760
+ const e = this.items.length === 1 ? this.msg.countOne : this.msg.countMany;
1761
+ return f`<div class="count" part="count">
1762
+ ${v(e, { n: this.items.length, max: this.maxFiles })}
1763
+ </div>`;
1764
+ }
1765
+ renderStatus(e) {
1766
+ const t = ee(e.file.size);
1767
+ if (e.status === "checking") return `${t} · ${this.msg.checking}`;
1768
+ if (e.status === "uploading") return `${t} · ${this.msg.uploading}`;
1769
+ if (e.status === "done") return `${t} · ${this.msg.uploaded}`;
1770
+ if (e.status === "error")
1771
+ return `${t} · ${e.error || this.msg.failedLabel}`;
1772
+ const o = e.pages ? ` · ${v(this.msg.pagesLabel, { n: e.pages })}` : "";
1773
+ return t + o;
1774
+ }
1775
+ renderRow(e) {
1776
+ const t = this.allowRename && e.status === "ready";
1777
+ return e.status === "uploading" || e.status, f`<div class="row" part="file">
1778
+ <div class="chip" part="file-type">
1779
+ ${e.preview ? f`<img class="thumb" src=${e.preview} alt="" part="preview" />` : Ae(e.name) || "FILE"}
1780
+ </div>
1781
+ <div class="meta">
1782
+ ${this.editing === e.key ? f`<input
1783
+ class="name-input"
1784
+ .value=${e.name}
1785
+ autofocus
1786
+ @keydown=${(o) => {
1787
+ o.key === "Enter" ? this.commitRename(e, o.target.value) : o.key === "Escape" && (this.editing = "");
1788
+ }}
1789
+ @blur=${(o) => this.commitRename(e, o.target.value)}
1790
+ />` : t ? f`<button
1791
+ class="name"
1792
+ title=${this.msg.rename}
1793
+ @click=${() => {
1794
+ this.editing = e.key;
1795
+ }}
1796
+ >
1797
+ ${e.name}
1798
+ </button>` : f`<div class="name">${e.name}</div>`}
1799
+ <div class="sz" data-state=${e.status}>${this.renderStatus(e)}</div>
1800
+ ${e.status === "uploading" ? f`<div class="bar" part="progress">
1801
+ <div class="bar-fill" style="width:${e.percent}%"></div>
1802
+ </div>` : x}
1803
+ </div>
1804
+ <div class="row-act">
1805
+ ${e.status === "error" ? f`<button class="link-sm" @click=${() => void this.upload()}>
1806
+ ${this.msg.retry}
1807
+ </button>` : x}
1808
+ ${e.status === "uploading" || e.status === "done" ? x : f`<button class="link-sm" @click=${() => this.removeItem(e.key)}>
1809
+ ${this.msg.remove}
1810
+ </button>`}
1811
+ </div>
1812
+ </div>`;
1813
+ }
1814
+ renderRows() {
1815
+ return this.items.length ? f`<div class="rows" part="files">
1816
+ ${this.items.map((e) => this.renderRow(e))}
1817
+ </div>` : x;
1818
+ }
1819
+ renderDropzone() {
1820
+ return f`<div class="drop" part="dropzone" data-drag=${String(this.dragging)}>
1821
+ <div class="arrow" aria-hidden="true">↑</div>
1822
+ <div class="drop-title">${this.msg.dropTitle}</div>
1823
+ <button class="link" @click=${this.open}>${this.msg.dropSub}</button>
1824
+ ${this.hint ? f`<div class="hint">${this.hint}</div>` : x}
1825
+ </div>`;
1826
+ }
1827
+ renderUploadCta() {
1828
+ const e = this.pendingCount;
1829
+ if (this.autoUpload || !e && !this.busy) return x;
1830
+ const t = e === 1 ? this.msg.uploadCtaOne : this.msg.uploadCtaMany;
1831
+ return f`<button
1832
+ class="primary wide"
1833
+ part="submit"
1834
+ ?disabled=${this.busy || this.checking}
1835
+ @click=${() => void this.upload()}
1836
+ >
1837
+ ${this.busy ? this.msg.uploading : v(t, { n: e })}
1838
+ </button>`;
1839
+ }
1840
+ /**
1841
+ * The whole card is the drop surface. Once files are staged the big zone is
1842
+ * replaced by the "add more" control, and a drop should still land.
1843
+ */
1844
+ renderFull() {
1845
+ const e = this.dropzone && !this.items.length && this.canAddMore;
1846
+ return f`<div
1847
+ class="card"
1848
+ part="card"
1849
+ @dragover=${this.onDragOver}
1850
+ @dragleave=${this.onDragLeave}
1851
+ @drop=${this.onDrop}
1852
+ >
1853
+ ${this.logoUrl || this.logoText || this.heading || this.description ? f`<div class="head-block">
1854
+ ${this.renderLogo()}
1855
+ ${this.heading ? f`<div class="title">${this.heading}</div>` : x}
1856
+ ${this.description ? f`<div class="sub">${this.description}</div>` : x}
1857
+ </div>` : x}
1858
+ ${this.renderCount()} ${this.renderNotice()} ${this.renderRows()}
1859
+ ${e ? this.renderDropzone() : x}
1860
+ ${!e && this.canAddMore ? f`<button class="add-more" @click=${this.open}>${this.msg.addMore}</button>` : x}
1861
+ ${this.renderUploadCta()} ${this.renderBranding()}
1862
+ </div>`;
1863
+ }
1864
+ renderCompact() {
1865
+ return f`<div
1866
+ class="card"
1867
+ part="card"
1868
+ @dragover=${this.onDragOver}
1869
+ @dragleave=${this.onDragLeave}
1870
+ @drop=${this.onDrop}
1871
+ >
1872
+ <div class="between">
1873
+ <span class="sec-title">${this.heading || this.msg.attachments}</span>
1874
+ <span class="count">${this.items.length} / ${this.maxFiles}</span>
1875
+ </div>
1876
+ ${this.dropzone ? f`<div class="strip" part="dropzone" data-drag=${String(this.dragging)}>
1877
+ <span class="strip-label">${this.msg.dropOrChoose}</span>
1878
+ <button class="secondary" ?disabled=${!this.canAddMore} @click=${this.open}>
1879
+ ${this.msg.chooseFiles}
1880
+ </button>
1881
+ </div>` : f`<button class="secondary" ?disabled=${!this.canAddMore} @click=${this.open}>
1882
+ ${this.msg.chooseFiles}
1883
+ </button>`}
1884
+ ${this.hint ? f`<div class="hint">${this.hint}</div>` : x} ${this.renderNotice()}
1885
+ ${this.renderRows()} ${this.renderUploadCta()} ${this.renderBranding()}
1886
+ </div>`;
1887
+ }
1888
+ renderButton() {
1889
+ const e = this.items[this.items.length - 1];
1890
+ return f`<div class="button-view">
1891
+ <button class="primary" ?disabled=${this.busy || !this.canAddMore} @click=${this.open}>
1892
+ ${this.busy ? this.msg.uploading : this.msg.chooseFile}
1893
+ </button>
1894
+ ${e && e.status !== "ready" ? f`<div class="sz" data-state=${e.status}>${this.renderStatus(e)}</div>` : x}
1895
+ ${this.renderNotice()}
1896
+ </div>`;
1897
+ }
1898
+ render() {
1899
+ return f`${this.renderInput()}${this.view === "button" ? this.renderButton() : this.view === "compact" ? this.renderCompact() : this.renderFull()}`;
1900
+ }
1901
+ }, k = new WeakMap(), z = new WeakMap(), $ = new WeakMap(), U = new WeakMap(), S = new WeakMap(), C = new WeakMap(), M = new WeakMap(), L = new WeakMap(), T = new WeakMap(), F = new WeakMap(), O = new WeakMap(), D = new WeakMap(), j = new WeakMap(), A = new WeakMap(), E = new WeakMap(), N = new WeakMap(), B = new WeakMap(), P = new WeakMap(), R = new WeakMap(), I = new WeakMap(), G = new WeakMap(), _ = new WeakMap(), K = new WeakMap(), W = new WeakMap(), Y = new WeakMap(), q = new WeakMap(), H = new WeakMap(), V = new WeakMap(), J = new WeakMap(), X = new WeakMap(), ye);
1902
+ Ze(s, "styles", [
1903
+ Te,
1904
+ Fe,
1905
+ se`
1906
+ .card {
1907
+ display: flex;
1908
+ flex-direction: column;
1909
+ gap: 14px;
1910
+ box-sizing: border-box;
1911
+ padding: var(--sb-pad, 20px);
1912
+ background: var(--sb-surface, #ffffff);
1913
+ color: var(--sb-ink, #16181a);
1914
+ border: 1px solid var(--sb-border, #e4e6e9);
1915
+ border-radius: calc(var(--sb-radius, 4px) + 4px);
1916
+ }
1917
+
1918
+ .logo-img {
1919
+ display: block;
1920
+ align-self: flex-start;
1921
+ height: var(--sb-logo-height, 20px);
1922
+ width: auto;
1923
+ max-width: 100%;
1924
+ }
1925
+
1926
+ .brand-mark {
1927
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
1928
+ font-size: 13px;
1929
+ letter-spacing: 0.08em;
1930
+ text-transform: uppercase;
1931
+ color: var(--sb-ink, #16181a);
1932
+ }
1933
+
1934
+ .head-block {
1935
+ display: flex;
1936
+ flex-direction: column;
1937
+ gap: 6px;
1938
+ }
1939
+
1940
+ .count {
1941
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
1942
+ font-size: 11.5px;
1943
+ letter-spacing: 0.06em;
1944
+ text-transform: uppercase;
1945
+ color: var(--sb-muted-ink, #61666c);
1946
+ }
1947
+
1948
+ /* ── dropzone ─────────────────────────────────────── */
1949
+ .drop {
1950
+ display: flex;
1951
+ flex-direction: column;
1952
+ align-items: center;
1953
+ gap: 6px;
1954
+ padding: 30px 20px;
1955
+ text-align: center;
1956
+ border: 1px dashed var(--sb-border-strong, #cdd1d6);
1957
+ border-radius: calc(var(--sb-radius, 4px) + 2px);
1958
+ background: var(--sb-surface, #ffffff);
1959
+ transition:
1960
+ border-color 0.15s,
1961
+ background 0.15s;
1962
+ }
1963
+
1964
+ .drop[data-drag="true"] {
1965
+ border-color: var(--sb-accent, #111111);
1966
+ background: var(--sb-surface-alt, #fafafa);
1967
+ }
1968
+
1969
+ .arrow {
1970
+ display: flex;
1971
+ align-items: center;
1972
+ justify-content: center;
1973
+ width: 42px;
1974
+ height: 42px;
1975
+ margin-bottom: 4px;
1976
+ font-size: 18px;
1977
+ line-height: 1;
1978
+ border: 1px solid var(--sb-border, #e4e6e9);
1979
+ border-radius: 50%;
1980
+ color: var(--sb-ink, #16181a);
1981
+ }
1982
+
1983
+ .drop-title {
1984
+ font-size: 14px;
1985
+ font-weight: 600;
1986
+ color: var(--sb-ink, #16181a);
1987
+ }
1988
+
1989
+ /* the compact single-line dropzone */
1990
+ .strip {
1991
+ display: flex;
1992
+ align-items: center;
1993
+ justify-content: space-between;
1994
+ gap: 12px;
1995
+ padding: 10px 12px;
1996
+ border: 1px solid var(--sb-border, #e4e6e9);
1997
+ border-radius: calc(var(--sb-radius, 4px) + 2px);
1998
+ background: var(--sb-surface-alt, #fafafa);
1999
+ transition:
2000
+ border-color 0.15s,
2001
+ background 0.15s;
2002
+ }
2003
+
2004
+ .strip[data-drag="true"] {
2005
+ border-color: var(--sb-accent, #111111);
2006
+ }
2007
+
2008
+ .strip-label {
2009
+ font-size: 14px;
2010
+ color: var(--sb-muted-ink, #61666c);
2011
+ }
2012
+
2013
+ /* ── file rows ────────────────────────────────────── */
2014
+ .rows {
2015
+ display: flex;
2016
+ flex-direction: column;
2017
+ }
2018
+
2019
+ .row {
2020
+ display: flex;
2021
+ align-items: center;
2022
+ gap: 12px;
2023
+ padding: 12px 0;
2024
+ border-top: 1px solid var(--sb-border, #e4e6e9);
2025
+ }
2026
+
2027
+ .rows .row:first-child {
2028
+ border-top: none;
2029
+ }
2030
+
2031
+ .chip {
2032
+ display: flex;
2033
+ align-items: center;
2034
+ justify-content: center;
2035
+ flex: 0 0 auto;
2036
+ width: 46px;
2037
+ height: 46px;
2038
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
2039
+ font-size: 10.5px;
2040
+ letter-spacing: 0.04em;
2041
+ color: var(--sb-muted-ink, #61666c);
2042
+ background: var(--sb-surface-alt, #fafafa);
2043
+ border: 1px solid var(--sb-border, #e4e6e9);
2044
+ border-radius: var(--sb-radius, 4px);
2045
+ overflow: hidden;
2046
+ }
2047
+
2048
+ .thumb {
2049
+ display: block;
2050
+ width: 100%;
2051
+ height: 100%;
2052
+ object-fit: cover;
2053
+ }
2054
+
2055
+ .meta {
2056
+ flex: 1;
2057
+ min-width: 0;
2058
+ display: flex;
2059
+ flex-direction: column;
2060
+ gap: 4px;
2061
+ }
2062
+
2063
+ .name {
2064
+ font-size: 14px;
2065
+ font-weight: 500;
2066
+ color: var(--sb-ink, #16181a);
2067
+ overflow: hidden;
2068
+ text-overflow: ellipsis;
2069
+ white-space: nowrap;
2070
+ }
2071
+
2072
+ button.name {
2073
+ align-self: flex-start;
2074
+ max-width: 100%;
2075
+ padding: 0;
2076
+ border: none;
2077
+ background: none;
2078
+ text-align: left;
2079
+ border-radius: 0;
2080
+ }
2081
+
2082
+ button.name:hover {
2083
+ text-decoration: underline;
2084
+ text-underline-offset: 3px;
2085
+ }
2086
+
2087
+ .name-input {
2088
+ font-size: 14px;
2089
+ padding: 6px 8px;
2090
+ }
2091
+
2092
+ .sz {
2093
+ font-size: 12px;
2094
+ color: var(--sb-muted-ink, #61666c);
2095
+ }
2096
+
2097
+ .sz[data-state="error"] {
2098
+ color: var(--sb-danger, #b4231a);
2099
+ }
2100
+
2101
+ .sz[data-state="done"] {
2102
+ color: var(--sb-ok, #0f6b4a);
2103
+ }
2104
+
2105
+ .bar {
2106
+ height: 3px;
2107
+ margin-top: 2px;
2108
+ border-radius: 999px;
2109
+ background: var(--sb-border, #e4e6e9);
2110
+ overflow: hidden;
2111
+ }
2112
+
2113
+ .bar-fill {
2114
+ height: 100%;
2115
+ background: var(--sb-accent, #111111);
2116
+ transition: width 0.2s linear;
2117
+ }
2118
+
2119
+ .row-act {
2120
+ flex: 0 0 auto;
2121
+ display: flex;
2122
+ align-items: center;
2123
+ gap: 10px;
2124
+ }
2125
+
2126
+ /* ── the dashed "add more" affordance ─────────────── */
2127
+ button.add-more {
2128
+ width: 100%;
2129
+ padding: 14px;
2130
+ color: var(--sb-ink, #16181a);
2131
+ background: none;
2132
+ border: 1px dashed var(--sb-border-strong, #cdd1d6);
2133
+ border-radius: calc(var(--sb-radius, 4px) + 2px);
2134
+ }
2135
+
2136
+ button.add-more:hover:not(:disabled) {
2137
+ background: var(--sb-surface-alt, #fafafa);
2138
+ }
2139
+
2140
+ button.wide {
2141
+ width: 100%;
2142
+ padding: 13px;
2143
+ font-size: 14px;
2144
+ }
2145
+
2146
+ .branding {
2147
+ text-align: center;
2148
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
2149
+ font-size: 10.5px;
2150
+ letter-spacing: 0.06em;
2151
+ color: var(--sb-muted-ink, #61666c);
2152
+ }
2153
+
2154
+ .branding a {
2155
+ color: inherit;
2156
+ text-decoration: none;
2157
+ }
2158
+
2159
+ .branding a:hover {
2160
+ color: var(--sb-ink, #16181a);
2161
+ text-decoration: underline;
2162
+ text-underline-offset: 3px;
2163
+ }
2164
+
2165
+ /* the button view is just a control, not a card */
2166
+ :host([view="button"]) {
2167
+ display: inline-block;
2168
+ }
2169
+
2170
+ .button-view {
2171
+ display: flex;
2172
+ flex-direction: column;
2173
+ gap: 8px;
2174
+ }
2175
+ `
2176
+ ]);
2177
+ p([
2178
+ g({ attribute: !1 })
2179
+ ], s.prototype, "client", 1);
2180
+ p([
2181
+ g({ attribute: !1 })
2182
+ ], s.prototype, "messages", 1);
2183
+ p([
2184
+ g({ reflect: !0 })
2185
+ ], s.prototype, "theme", 1);
2186
+ p([
2187
+ g({ reflect: !0 })
2188
+ ], s.prototype, "density", 1);
2189
+ p([
2190
+ g({ reflect: !0 })
2191
+ ], s.prototype, "view", 1);
2192
+ p([
2193
+ g({ converter: le })
2194
+ ], s.prototype, "dropzone", 1);
2195
+ p([
2196
+ g({ converter: le, attribute: "allow-rename" })
2197
+ ], s.prototype, "allowRename", 1);
2198
+ p([
2199
+ g({ type: Boolean, attribute: "auto-upload" })
2200
+ ], s.prototype, "autoUpload", 1);
2201
+ p([
2202
+ g({ converter: le })
2203
+ ], s.prototype, "branding", 1);
2204
+ p([
2205
+ g({ attribute: "logo-url" })
2206
+ ], s.prototype, "logoUrl", 1);
2207
+ p([
2208
+ g({ attribute: "logo-text" })
2209
+ ], s.prototype, "logoText", 1);
2210
+ p([
2211
+ g()
2212
+ ], s.prototype, "heading", 1);
2213
+ p([
2214
+ g()
2215
+ ], s.prototype, "description", 1);
2216
+ p([
2217
+ g({ type: Number, attribute: "max-files" })
2218
+ ], s.prototype, "maxFiles", 1);
2219
+ p([
2220
+ g({ attribute: "max-size" })
2221
+ ], s.prototype, "maxSize", 1);
2222
+ p([
2223
+ g({ attribute: "min-size" })
2224
+ ], s.prototype, "minSize", 1);
2225
+ p([
2226
+ g()
2227
+ ], s.prototype, "accept", 1);
2228
+ p([
2229
+ g({ converter: de })
2230
+ ], s.prototype, "rules", 1);
2231
+ p([
2232
+ g()
2233
+ ], s.prototype, "bucket", 1);
2234
+ p([
2235
+ g({ converter: de })
2236
+ ], s.prototype, "metadata", 1);
2237
+ p([
2238
+ g({ converter: de })
2239
+ ], s.prototype, "options", 1);
2240
+ p([
2241
+ g({ type: Boolean, attribute: "public-read" })
2242
+ ], s.prototype, "publicRead", 1);
2243
+ p([
2244
+ g({ attribute: "redirect-url" })
2245
+ ], s.prototype, "redirectUrl", 1);
2246
+ p([
2247
+ g({ attribute: !1 })
2248
+ ], s.prototype, "onComplete", 1);
2249
+ p([
2250
+ g({ attribute: !1 })
2251
+ ], s.prototype, "onError", 1);
2252
+ p([
2253
+ Z()
2254
+ ], s.prototype, "items", 1);
2255
+ p([
2256
+ Z()
2257
+ ], s.prototype, "notice", 1);
2258
+ p([
2259
+ Z()
2260
+ ], s.prototype, "busy", 1);
2261
+ p([
2262
+ Z()
2263
+ ], s.prototype, "dragging", 1);
2264
+ p([
2265
+ Z()
2266
+ ], s.prototype, "editing", 1);
2267
+ s = p([
2268
+ Me("singlebase-uploader")
2269
+ ], s);
2270
+ function Qe(r) {
2271
+ return !r.type.startsWith("image/") || typeof URL.createObjectURL != "function" ? "" : URL.createObjectURL(r);
2272
+ }
2273
+ function w(r) {
2274
+ r.preview && URL.revokeObjectURL(r.preview);
2275
+ }
2276
+ function et(r) {
2277
+ return r instanceof Error ? r.message : "";
2278
+ }
2279
+ export {
2280
+ s as S,
2281
+ he as T,
2282
+ Ke as a,
2283
+ De as b,
2284
+ me as d,
2285
+ _e as i,
2286
+ Oe as r,
2287
+ Fe as s,
2288
+ Te as t
2289
+ };
2290
+ //# sourceMappingURL=uploader-D-Da1trc.js.map