@helixui/library 2.1.2-next.50 → 2.1.2-next.52

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 (62) hide show
  1. package/custom-elements.json +235 -236
  2. package/dist/components/hx-counter/hx-counter.d.ts +20 -0
  3. package/dist/components/hx-counter/hx-counter.d.ts.map +1 -1
  4. package/dist/components/hx-counter/index.js +1 -1
  5. package/dist/components/hx-file-upload/hx-file-upload.d.ts +3 -1
  6. package/dist/components/hx-file-upload/hx-file-upload.d.ts.map +1 -1
  7. package/dist/components/hx-file-upload/hx-file-upload.styles.d.ts.map +1 -1
  8. package/dist/components/hx-file-upload/index.js +1 -1
  9. package/dist/components/hx-form/hx-form.d.ts.map +1 -1
  10. package/dist/components/hx-form/index.js +1 -1
  11. package/dist/components/hx-list/hx-list-item.styles.d.ts.map +1 -1
  12. package/dist/components/hx-list/index.js +1 -1
  13. package/dist/components/hx-meter/hx-meter.styles.d.ts.map +1 -1
  14. package/dist/components/hx-meter/index.js +1 -1
  15. package/dist/components/hx-phi-field/hx-phi-field.d.ts +2 -1
  16. package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
  17. package/dist/components/hx-phi-field/hx-phi-field.styles.d.ts.map +1 -1
  18. package/dist/components/hx-phi-field/index.js +1 -1
  19. package/dist/components/hx-popover/index.js +1 -1
  20. package/dist/components/hx-popup/hx-popup.d.ts.map +1 -1
  21. package/dist/components/hx-popup/index.js +1 -1
  22. package/dist/components/hx-stat/hx-stat.d.ts +3 -0
  23. package/dist/components/hx-stat/hx-stat.d.ts.map +1 -1
  24. package/dist/components/hx-stat/hx-stat.styles.d.ts.map +1 -1
  25. package/dist/components/hx-stat/index.js +1 -1
  26. package/dist/css/helix-all.css +117 -7
  27. package/dist/css/helix-feedback.css +54 -6
  28. package/dist/css/helix-forms.css +48 -0
  29. package/dist/css/hx-file-upload.css +48 -0
  30. package/dist/css/hx-meter.css +7 -6
  31. package/dist/css/hx-phi-field.css +15 -1
  32. package/dist/css/hx-stat.css +47 -0
  33. package/dist/css/index.css +1 -1
  34. package/dist/css/manifest.json +6 -1
  35. package/dist/index.js +9 -9
  36. package/dist/shared/hx-card-BgXZXDuc.js.map +1 -1
  37. package/dist/shared/{hx-counter-CP42cSVK.js → hx-counter-B5NgKlw4.js} +77 -42
  38. package/dist/shared/hx-counter-B5NgKlw4.js.map +1 -0
  39. package/dist/shared/{hx-file-upload-Dwtu3WcB.js → hx-file-upload-Di_vpQaG.js} +156 -93
  40. package/dist/shared/hx-file-upload-Di_vpQaG.js.map +1 -0
  41. package/dist/shared/{hx-form-fJE-FJQV.js → hx-form-BM6PHsw3.js} +2 -8
  42. package/dist/shared/{hx-form-fJE-FJQV.js.map → hx-form-BM6PHsw3.js.map} +1 -1
  43. package/dist/shared/{hx-list-CoTDMp19.js → hx-list-Dnei26t4.js} +83 -51
  44. package/dist/shared/hx-list-Dnei26t4.js.map +1 -0
  45. package/dist/shared/{hx-meter-BvSJoqDp.js → hx-meter-BcVC9yrt.js} +13 -12
  46. package/dist/shared/hx-meter-BcVC9yrt.js.map +1 -0
  47. package/dist/shared/{hx-phi-field-BiJH3V-k.js → hx-phi-field-DD1qcBSO.js} +22 -5
  48. package/dist/shared/hx-phi-field-DD1qcBSO.js.map +1 -0
  49. package/dist/shared/{hx-popover-D63RXn5H.js → hx-popover-CydNuVkT.js} +15 -15
  50. package/dist/shared/{hx-popover-D63RXn5H.js.map → hx-popover-CydNuVkT.js.map} +1 -1
  51. package/dist/shared/{hx-popup-BQWMhvMO.js → hx-popup-DbzezTOd.js} +18 -18
  52. package/dist/shared/hx-popup-DbzezTOd.js.map +1 -0
  53. package/dist/shared/{hx-stat-DKD2E7An.js → hx-stat-DKlyBL_K.js} +97 -42
  54. package/dist/shared/hx-stat-DKlyBL_K.js.map +1 -0
  55. package/package.json +2 -2
  56. package/dist/shared/hx-counter-CP42cSVK.js.map +0 -1
  57. package/dist/shared/hx-file-upload-Dwtu3WcB.js.map +0 -1
  58. package/dist/shared/hx-list-CoTDMp19.js.map +0 -1
  59. package/dist/shared/hx-meter-BvSJoqDp.js.map +0 -1
  60. package/dist/shared/hx-phi-field-BiJH3V-k.js.map +0 -1
  61. package/dist/shared/hx-popup-BQWMhvMO.js.map +0 -1
  62. package/dist/shared/hx-stat-DKD2E7An.js.map +0 -1
@@ -1,10 +1,11 @@
1
- import { css as x, LitElement as g, nothing as p, html as c } from "lit";
1
+ import { css as b, nothing as c, html as f, LitElement as x } from "lit";
2
2
  import "./document-token-adoption-DuYNKd4k.js";
3
- import { property as a, state as b, query as _, customElement as y } from "lit/decorators.js";
3
+ import { property as n, state as g, query as _, customElement as y } from "lit/decorators.js";
4
4
  import { classMap as w } from "lit/directives/class-map.js";
5
5
  import { ifDefined as v } from "lit/directives/if-defined.js";
6
- import { repeat as $ } from "lit/directives/repeat.js";
7
- const z = x`
6
+ import { repeat as z } from "lit/directives/repeat.js";
7
+ import { m as $ } from "./aria-delegation-CBP9eQ0M.js";
8
+ const F = b`
8
9
  :host {
9
10
  display: block;
10
11
  }
@@ -166,6 +167,8 @@ const z = x`
166
167
  display: inline-flex;
167
168
  align-items: center;
168
169
  justify-content: center;
170
+ min-width: 44px;
171
+ min-height: 44px;
169
172
  padding: var(--hx-space-1, 0.25rem);
170
173
  border: none;
171
174
  border-radius: var(--hx-border-radius-sm, 0.25rem);
@@ -245,15 +248,61 @@ const z = x`
245
248
  color: var(--hx-file-upload-error-color, var(--hx-color-error-text, #b91c1c));
246
249
  line-height: var(--hx-line-height-normal, 1.5);
247
250
  }
251
+
252
+ /* ─── Forced colors (Windows High Contrast / Forced Colors Mode) ─── */
253
+
254
+ @media (forced-colors: active) {
255
+ .dropzone {
256
+ border: 2px dashed ButtonText;
257
+ background-color: Canvas;
258
+ color: ButtonText;
259
+ }
260
+
261
+ .dropzone--drag-over {
262
+ border: 2px solid Highlight;
263
+ outline: none;
264
+ background-color: Canvas;
265
+ }
266
+
267
+ .dropzone--error {
268
+ border: 2px solid LinkText;
269
+ }
270
+
271
+ .dropzone:focus-visible {
272
+ outline: 2px solid Highlight;
273
+ outline-offset: 2px;
274
+ }
275
+
276
+ .progress-bar {
277
+ background: Highlight;
278
+ forced-color-adjust: none;
279
+ }
280
+
281
+ .file-item__remove:hover {
282
+ outline: 2px solid Highlight;
283
+ background-color: transparent;
284
+ color: ButtonText;
285
+ }
286
+
287
+ .file-item__remove:focus-visible {
288
+ outline: 2px solid Highlight;
289
+ }
290
+
291
+ :host([disabled]) .dropzone {
292
+ border-color: GrayText;
293
+ color: GrayText;
294
+ opacity: 1;
295
+ }
296
+ }
248
297
  `;
249
- var F = Object.defineProperty, D = Object.getOwnPropertyDescriptor, o = (e, r, t, s) => {
250
- for (var l = s > 1 ? void 0 : s ? D(r, t) : r, d = e.length - 1, n; d >= 0; d--)
251
- (n = e[d]) && (l = (s ? n(r, t, l) : n(l)) || l);
252
- return s && l && F(r, t, l), l;
298
+ var D = Object.defineProperty, k = Object.getOwnPropertyDescriptor, l = (e, r, t, i) => {
299
+ for (var s = i > 1 ? void 0 : i ? k(r, t) : r, a = e.length - 1, d; a >= 0; a--)
300
+ (d = e[a]) && (s = (i ? d(r, t, s) : d(s)) || s);
301
+ return i && s && D(r, t, s), s;
253
302
  };
254
- let k = 0, i = class extends g {
303
+ let C = 0, o = class extends $(x) {
255
304
  constructor() {
256
- super(), this.name = "", this.accept = "", this.maxSize = 0, this.maxFiles = 0, this.multiple = !1, this.label = "", this.disabled = !1, this.error = "", this.labelDropzone = "Drag files here or click to browse", this.labelFileList = "Selected files", this.labelUploadProgress = (e, r) => `Upload progress for ${e}: ${r}%`, this.labelDragDetected = "File detected. Release to upload.", this._files = [], this._dragOver = !1, this._hasFileListSlot = !1, this._baseId = `hx-file-upload-${++k}`, this._labelId = `${this._baseId}-label`, this._errorId = `${this._baseId}-error`, this._dropzoneId = `${this._baseId}-dropzone`, this._liveId = `${this._baseId}-live`, this._internals = this.attachInternals();
305
+ super(), this.name = "", this.accept = "", this.maxSize = 0, this.maxFiles = 0, this.multiple = !1, this.label = "", this.disabled = !1, this.error = "", this.labelDropzone = "Drag files here or click to browse", this.labelFileList = "Selected files", this.labelUploadProgress = (e, r) => `Upload progress for ${e}: ${r}%`, this.labelDragDetected = "File detected. Release to upload.", this._files = [], this._dragOver = !1, this._hasFileListSlot = !1, this._baseId = `hx-file-upload-${++C}`, this._labelId = `${this._baseId}-label`, this._errorId = `${this._baseId}-error`, this._dropzoneId = `${this._baseId}-dropzone`, this._liveId = `${this._baseId}-live`, this._internals = this.attachInternals();
257
306
  }
258
307
  // ─── Slot Handling ───
259
308
  /** @internal */
@@ -341,8 +390,8 @@ let k = 0, i = class extends g {
341
390
  if (t.startsWith(".")) {
342
391
  if (e.name.toLowerCase().endsWith(t)) return !0;
343
392
  } else if (t.endsWith("/*")) {
344
- const s = t.slice(0, -2);
345
- if (e.type.toLowerCase().startsWith(s)) return !0;
393
+ const i = t.slice(0, -2);
394
+ if (e.type.toLowerCase().startsWith(i)) return !0;
346
395
  } else if (e.type.toLowerCase() === t) return !0;
347
396
  return !1;
348
397
  }
@@ -350,20 +399,20 @@ let k = 0, i = class extends g {
350
399
  /** @internal */
351
400
  _processFiles(e) {
352
401
  if (this.disabled) return;
353
- const r = this.multiple ? e : e.slice(0, 1), t = [], s = [], l = [];
354
- for (const h of r) {
355
- const m = this._validateFile(h);
356
- m ? (s.push(h), l.push(m)) : t.push(h);
402
+ const r = this.multiple ? e : e.slice(0, 1), t = [], i = [], s = [];
403
+ for (const p of r) {
404
+ const m = this._validateFile(p);
405
+ m ? (i.push(p), s.push(m)) : t.push(p);
357
406
  }
358
- if (s.length > 0 && this.dispatchEvent(
407
+ if (i.length > 0 && this.dispatchEvent(
359
408
  new CustomEvent("hx-error", {
360
409
  bubbles: !0,
361
410
  composed: !0,
362
- detail: { message: l.join(" "), files: s }
411
+ detail: { message: s.join(" "), files: i }
363
412
  })
364
413
  ), t.length === 0) return;
365
- const d = this.multiple ? this._files.length : 0, n = this.maxFiles > 0 ? Math.max(0, this.maxFiles - d) : t.length, f = t.slice(0, n);
366
- if (f.length === 0 && this.maxFiles > 0) {
414
+ const a = this.multiple ? this._files.length : 0, d = this.maxFiles > 0 ? Math.max(0, this.maxFiles - a) : t.length, h = t.slice(0, d);
415
+ if (h.length === 0 && this.maxFiles > 0) {
367
416
  this.dispatchEvent(
368
417
  new CustomEvent("hx-error", {
369
418
  bubbles: !0,
@@ -376,17 +425,17 @@ let k = 0, i = class extends g {
376
425
  );
377
426
  return;
378
427
  }
379
- if (f.length > 0) {
380
- const h = f.map((m) => ({ file: m, progress: 0 }));
381
- this.multiple ? this._files = [...this._files, ...h] : this._files = h, this.dispatchEvent(
428
+ if (h.length > 0) {
429
+ const p = h.map((m) => ({ file: m, progress: 0 }));
430
+ this.multiple ? this._files = [...this._files, ...p] : this._files = p, this.dispatchEvent(
382
431
  new CustomEvent("hx-upload", {
383
432
  bubbles: !0,
384
433
  composed: !0,
385
- detail: { files: f }
434
+ detail: { files: h }
386
435
  })
387
436
  );
388
437
  }
389
- const u = t.slice(n);
438
+ const u = t.slice(d);
390
439
  u.length > 0 && this.maxFiles > 0 && this.dispatchEvent(
391
440
  new CustomEvent("hx-error", {
392
441
  bubbles: !0,
@@ -408,7 +457,7 @@ let k = 0, i = class extends g {
408
457
  if (e < 0 || e >= this._files.length) return;
409
458
  const t = Math.max(0, Math.min(100, r));
410
459
  this._files = this._files.map(
411
- (s, l) => l === e ? { ...s, progress: t } : s
460
+ (i, s) => s === e ? { ...i, progress: t } : i
412
461
  );
413
462
  }
414
463
  /**
@@ -424,10 +473,10 @@ let k = 0, i = class extends g {
424
473
  }
425
474
  /** @internal */
426
475
  _handleDragLeave(e) {
427
- var s;
476
+ var i;
428
477
  const r = e.relatedTarget;
429
478
  if (r && this.contains(r)) return;
430
- const t = (s = this.shadowRoot) == null ? void 0 : s.querySelector(".dropzone");
479
+ const t = (i = this.shadowRoot) == null ? void 0 : i.querySelector(".dropzone");
431
480
  t && t.contains(r) || (this._dragOver = !1);
432
481
  }
433
482
  /** @internal */
@@ -463,13 +512,26 @@ let k = 0, i = class extends g {
463
512
  const r = this._files[e];
464
513
  if (!r) return;
465
514
  const t = r.file;
466
- this._files = this._files.filter((s, l) => l !== e), this.dispatchEvent(
515
+ this._files = this._files.filter((i, s) => s !== e), this.dispatchEvent(
467
516
  new CustomEvent("hx-remove", {
468
517
  bubbles: !0,
469
518
  composed: !0,
470
519
  detail: { file: t, index: e }
471
520
  })
472
- );
521
+ ), this.updateComplete.then(() => {
522
+ var i, s;
523
+ if (this._files.length === 0) {
524
+ const a = (i = this.shadowRoot) == null ? void 0 : i.querySelector('[part="dropzone"]');
525
+ a == null || a.focus();
526
+ } else {
527
+ const a = (s = this.shadowRoot) == null ? void 0 : s.querySelectorAll(".file-item__remove");
528
+ if (a && a.length > 0) {
529
+ const d = e < this._files.length ? e : this._files.length - 1, h = a[d];
530
+ h && h.focus();
531
+ }
532
+ }
533
+ }).catch(() => {
534
+ });
473
535
  }
474
536
  // ─── Formatters ───
475
537
  /** @internal */
@@ -479,12 +541,12 @@ let k = 0, i = class extends g {
479
541
  // ─── Render Helpers ───
480
542
  /** @internal */
481
543
  _renderFileList() {
482
- return this._hasFileListSlot ? p : this._files.length === 0 ? p : c`
544
+ return this._hasFileListSlot ? c : this._files.length === 0 ? c : f`
483
545
  <ul part="file-list" class="file-list" aria-label=${this.labelFileList}>
484
- ${$(
546
+ ${z(
485
547
  this._files,
486
548
  (e) => e.file.name + e.file.size,
487
- (e, r) => c`
549
+ (e, r) => f`
488
550
  <li part="file-item" class="file-item">
489
551
  <div class="file-item__row">
490
552
  <span class="file-item__name" title=${e.file.name}> ${e.file.name} </span>
@@ -540,13 +602,13 @@ let k = 0, i = class extends g {
540
602
  "dropzone--drag-over": this._dragOver,
541
603
  "dropzone--error": e
542
604
  }, t = this.label ? `${this.label} — ${this.labelDropzone}` : this.labelDropzone;
543
- return c`
605
+ return f`
544
606
  <div class="field">
545
- ${this.label ? c`
607
+ ${this.label ? f`
546
608
  <label part="label" class="field__label" id=${this._labelId} for=${this._dropzoneId}>
547
609
  ${this.label}
548
610
  </label>
549
- ` : p}
611
+ ` : c}
550
612
 
551
613
  <div
552
614
  part="dropzone"
@@ -554,9 +616,10 @@ let k = 0, i = class extends g {
554
616
  id=${this._dropzoneId}
555
617
  role="button"
556
618
  tabindex=${this.disabled ? "-1" : "0"}
557
- aria-label=${v(this.label ? void 0 : t)}
619
+ aria-label=${v(this.label ? void 0 : this.ariaLabel ?? t)}
558
620
  aria-labelledby=${v(this.label ? this._labelId : void 0)}
559
- aria-disabled=${this.disabled ? "true" : p}
621
+ aria-disabled=${this.disabled ? "true" : c}
622
+ aria-invalid=${e ? "true" : c}
560
623
  aria-describedby=${v(e ? this._errorId : void 0)}
561
624
  @click=${this._handleDropzoneClick}
562
625
  @keydown=${this._handleDropzoneKeyDown}
@@ -581,11 +644,11 @@ let k = 0, i = class extends g {
581
644
  <slot name="file-list" @slotchange=${this._handleFileListSlotChange}></slot>
582
645
 
583
646
  ${this._renderFileList()}
584
- ${e ? c`
647
+ ${e ? f`
585
648
  <div part="error" class="field__error" id=${this._errorId} role="alert">
586
649
  ${this.error}
587
650
  </div>
588
- ` : p}
651
+ ` : c}
589
652
 
590
653
  <div id=${this._liveId} class="sr-only" aria-live="polite" aria-atomic="true">
591
654
  ${this._dragOver ? this.labelDragDetected : ""}
@@ -594,60 +657,60 @@ let k = 0, i = class extends g {
594
657
  `;
595
658
  }
596
659
  };
597
- i.styles = [z];
598
- i.formAssociated = !0;
599
- o([
600
- a({ type: String })
601
- ], i.prototype, "name", 2);
602
- o([
603
- a({ type: String })
604
- ], i.prototype, "accept", 2);
605
- o([
606
- a({ type: Number, attribute: "max-size" })
607
- ], i.prototype, "maxSize", 2);
608
- o([
609
- a({ type: Number, attribute: "max-files" })
610
- ], i.prototype, "maxFiles", 2);
611
- o([
612
- a({ type: Boolean })
613
- ], i.prototype, "multiple", 2);
614
- o([
615
- a({ type: String })
616
- ], i.prototype, "label", 2);
617
- o([
618
- a({ type: Boolean, reflect: !0 })
619
- ], i.prototype, "disabled", 2);
620
- o([
621
- a({ type: String })
622
- ], i.prototype, "error", 2);
623
- o([
624
- a({ type: String, attribute: "label-dropzone" })
625
- ], i.prototype, "labelDropzone", 2);
626
- o([
627
- a({ type: String, attribute: "label-file-list" })
628
- ], i.prototype, "labelFileList", 2);
629
- o([
630
- a({ attribute: !1 })
631
- ], i.prototype, "labelUploadProgress", 2);
632
- o([
633
- a({ attribute: "label-drag-detected" })
634
- ], i.prototype, "labelDragDetected", 2);
635
- o([
636
- b()
637
- ], i.prototype, "_files", 2);
638
- o([
639
- b()
640
- ], i.prototype, "_dragOver", 2);
641
- o([
642
- b()
643
- ], i.prototype, "_hasFileListSlot", 2);
644
- o([
660
+ o.styles = [F];
661
+ o.formAssociated = !0;
662
+ l([
663
+ n({ type: String })
664
+ ], o.prototype, "name", 2);
665
+ l([
666
+ n({ type: String })
667
+ ], o.prototype, "accept", 2);
668
+ l([
669
+ n({ type: Number, attribute: "max-size" })
670
+ ], o.prototype, "maxSize", 2);
671
+ l([
672
+ n({ type: Number, attribute: "max-files" })
673
+ ], o.prototype, "maxFiles", 2);
674
+ l([
675
+ n({ type: Boolean })
676
+ ], o.prototype, "multiple", 2);
677
+ l([
678
+ n({ type: String })
679
+ ], o.prototype, "label", 2);
680
+ l([
681
+ n({ type: Boolean, reflect: !0 })
682
+ ], o.prototype, "disabled", 2);
683
+ l([
684
+ n({ type: String })
685
+ ], o.prototype, "error", 2);
686
+ l([
687
+ n({ type: String, attribute: "label-dropzone" })
688
+ ], o.prototype, "labelDropzone", 2);
689
+ l([
690
+ n({ type: String, attribute: "label-file-list" })
691
+ ], o.prototype, "labelFileList", 2);
692
+ l([
693
+ n({ attribute: !1 })
694
+ ], o.prototype, "labelUploadProgress", 2);
695
+ l([
696
+ n({ attribute: "label-drag-detected" })
697
+ ], o.prototype, "labelDragDetected", 2);
698
+ l([
699
+ g()
700
+ ], o.prototype, "_files", 2);
701
+ l([
702
+ g()
703
+ ], o.prototype, "_dragOver", 2);
704
+ l([
705
+ g()
706
+ ], o.prototype, "_hasFileListSlot", 2);
707
+ l([
645
708
  _(".file-input")
646
- ], i.prototype, "_fileInput", 2);
647
- i = o([
709
+ ], o.prototype, "_fileInput", 2);
710
+ o = l([
648
711
  y("hx-file-upload")
649
- ], i);
712
+ ], o);
650
713
  export {
651
- i as H
714
+ o as H
652
715
  };
653
- //# sourceMappingURL=hx-file-upload-Dwtu3WcB.js.map
716
+ //# sourceMappingURL=hx-file-upload-Di_vpQaG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-file-upload-Di_vpQaG.js","sources":["../../src/components/hx-file-upload/hx-file-upload.styles.ts","../../src/components/hx-file-upload/hx-file-upload.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFileUploadStyles = css`\n :host {\n display: block;\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-2, 0.5rem);\n font-family: var(--hx-font-family-sans, sans-serif);\n }\n\n /* ─── Label ─── */\n\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-color-neutral-700, #343a40);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Dropzone ─── */\n\n .dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--hx-space-2, 0.5rem);\n min-height: var(--hx-space-32, 8rem);\n padding: var(--hx-space-6, 1.5rem) var(--hx-space-4, 1rem);\n border: var(--hx-border-width-thin, 1px) dashed\n var(--hx-file-upload-dropzone-border-color, var(--hx-color-neutral-300, #ced4da));\n border-radius: var(--hx-file-upload-dropzone-border-radius, var(--hx-border-radius-lg, 0.5rem));\n background-color: var(--hx-file-upload-dropzone-bg, var(--hx-color-neutral-50, #f8f9fa));\n cursor: pointer;\n text-align: center;\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n background-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n user-select: none;\n color: var(--hx-color-neutral-600, #495057);\n font-size: var(--hx-font-size-sm, 0.875rem);\n }\n\n .dropzone:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-file-upload-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-color: var(\n --hx-file-upload-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n }\n\n .dropzone--drag-over {\n border-color: var(--hx-color-primary-500, #2563eb);\n background-color: var(\n --hx-file-upload-dropzone-active-bg,\n color-mix(\n in srgb,\n var(--hx-color-primary-500, #2563eb) 8%,\n var(--hx-color-neutral-0, #ffffff)\n )\n );\n border-style: solid;\n }\n\n .dropzone--error {\n border-color: var(--hx-file-upload-error-color, var(--hx-color-error-500, #dc3545));\n }\n\n @media (prefers-reduced-motion: reduce) {\n .dropzone {\n transition: none;\n }\n }\n\n /* ─── Hidden file input ─── */\n\n .file-input {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n\n /* ─── File list ─── */\n\n .file-list {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-2, 0.5rem);\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .file-list:empty {\n display: none;\n }\n\n /* ─── File item ─── */\n\n .file-item {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n border: var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #e9ecef);\n border-radius: var(--hx-border-radius-md, 0.375rem);\n background-color: var(--hx-color-neutral-0, #ffffff);\n }\n\n .file-item__row {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n }\n\n .file-item__name {\n flex: 1;\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-color-neutral-800, #212529);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .file-item__size {\n flex-shrink: 0;\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-color-neutral-500, #6c757d);\n }\n\n .file-item__remove {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 44px;\n min-height: 44px;\n padding: var(--hx-space-1, 0.25rem);\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n background: transparent;\n color: var(--hx-color-neutral-500, #6c757d);\n cursor: pointer;\n line-height: 1;\n transition:\n color var(--hx-transition-fast, 150ms ease),\n background-color var(--hx-transition-fast, 150ms ease);\n }\n\n .file-item__remove:hover {\n color: var(--hx-file-upload-error-color, var(--hx-color-error-text, #b91c1c));\n background-color: color-mix(in srgb, var(--hx-color-error-500, #dc3545) 8%, transparent);\n }\n\n .file-item__remove:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-file-upload-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .file-item__remove {\n transition: none;\n }\n }\n\n /* ─── Progress bar ─── */\n\n .progress-track {\n width: 100%;\n height: var(--hx-file-upload-progress-height, var(--hx-space-1, 0.25rem));\n background-color: var(--hx-color-neutral-200, #e9ecef);\n border-radius: var(--hx-border-radius-full, 9999px);\n overflow: hidden;\n }\n\n .progress-bar {\n height: 100%;\n width: 100%;\n background-color: var(--hx-file-upload-progress-color, var(--hx-color-primary-500, #2563eb));\n border-radius: inherit;\n transform-origin: left center;\n transform: scaleX(var(--_progress-ratio, 0));\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .progress-bar {\n transition: none;\n }\n }\n\n /* ─── Screen-reader only utility ─── */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n\n /* ─── Error message ─── */\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-file-upload-error-color, var(--hx-color-error-text, #b91c1c));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Forced colors (Windows High Contrast / Forced Colors Mode) ─── */\n\n @media (forced-colors: active) {\n .dropzone {\n border: 2px dashed ButtonText;\n background-color: Canvas;\n color: ButtonText;\n }\n\n .dropzone--drag-over {\n border: 2px solid Highlight;\n outline: none;\n background-color: Canvas;\n }\n\n .dropzone--error {\n border: 2px solid LinkText;\n }\n\n .dropzone:focus-visible {\n outline: 2px solid Highlight;\n outline-offset: 2px;\n }\n\n .progress-bar {\n background: Highlight;\n forced-color-adjust: none;\n }\n\n .file-item__remove:hover {\n outline: 2px solid Highlight;\n background-color: transparent;\n color: ButtonText;\n }\n\n .file-item__remove:focus-visible {\n outline: 2px solid Highlight;\n }\n\n :host([disabled]) .dropzone {\n border-color: GrayText;\n color: GrayText;\n opacity: 1;\n }\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { mixinDelegatesAria } from '../../mixins/index.js';\nimport { helixFileUploadStyles } from './hx-file-upload.styles.js';\n\n// Module-level counter for stable, SSR-safe IDs (avoids Math.random() hydration mismatch)\nlet _hxFileUploadIdCounter = 0;\n\ninterface FileEntry {\n file: File;\n progress: number;\n}\n\n/**\n * A drag-and-drop file upload component with client-side validation,\n * file list management, per-file progress, and native form association.\n *\n * @summary Form-associated file upload dropzone with drag-and-drop, validation, and progress tracking.\n *\n * @tag hx-file-upload\n *\n * @slot - Default dropzone content. Replaces the built-in \"Drag files here or click to browse\" prompt.\n * @slot file-list - Custom file list display. When provided, the built-in file list is hidden.\n *\n * @fires {CustomEvent<{files: File[]}>} hx-upload - Dispatched when valid files are selected via drag-and-drop or the file picker.\n * @fires {CustomEvent<{file: File, index: number}>} hx-remove - Dispatched when a file is removed from the list.\n * @fires {CustomEvent<{message: string, files: File[]}>} hx-error - Dispatched when file validation fails (type or size constraint).\n *\n * @csspart dropzone - The drag-and-drop target area.\n * @csspart file-list - The container wrapping the list of selected files.\n * @csspart file-item - An individual file entry in the list.\n * @csspart progress - The progress bar track for a file item.\n * @csspart label - The visible label element.\n * @csspart error - The error message container below the dropzone.\n *\n * @cssprop [--hx-file-upload-dropzone-bg=var(--hx-color-neutral-50)] - Dropzone background color.\n * @cssprop [--hx-file-upload-dropzone-border-color=var(--hx-color-neutral-300)] - Dropzone border color.\n * @cssprop [--hx-file-upload-dropzone-border-radius=var(--hx-border-radius-lg)] - Dropzone border radius.\n * @cssprop [--hx-file-upload-dropzone-active-bg] - Dropzone background when a file is dragged over.\n * @cssprop [--hx-file-upload-progress-color=var(--hx-color-primary-500)] - Progress bar fill color.\n * @cssprop [--hx-file-upload-error-color=var(--hx-color-error-500)] - Error state and remove-button hover color.\n */\n@customElement('hx-file-upload')\nexport class HelixFileUpload extends mixinDelegatesAria(LitElement) {\n static override styles = [helixFileUploadStyles];\n\n // ─── Form Association ───\n\n /** Marks this element as form-associated for ElementInternals support. @internal */\n static formAssociated = true;\n\n /** Holds the ElementInternals instance used for form value and validity management. @internal */\n private _internals: ElementInternals;\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n }\n\n // ─── Properties ───\n\n /**\n * The form field name used during form submission.\n * @attr name\n */\n @property({ type: String })\n name = '';\n\n /**\n * Accepted file types as a comma-separated list of MIME types or extensions.\n * Mirrors the native `<input type=\"file\" accept>` attribute.\n * @attr accept\n */\n @property({ type: String })\n accept = '';\n\n /**\n * Maximum allowed file size in bytes. 0 means unlimited.\n * @attr max-size\n */\n @property({ type: Number, attribute: 'max-size' })\n maxSize = 0;\n\n /**\n * Maximum number of files that can be selected. 0 means unlimited.\n * @attr max-files\n */\n @property({ type: Number, attribute: 'max-files' })\n maxFiles = 0;\n\n /**\n * Whether multiple files may be selected at once.\n * @attr multiple\n */\n @property({ type: Boolean })\n multiple = false;\n\n /**\n * Visible label text for the dropzone.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Whether the component is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message displayed below the dropzone. Also puts the dropzone in an error visual state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Instructional text shown in the dropzone when no custom slot content is provided.\n * Also used as the accessible label for the dropzone.\n * @attr label-dropzone\n */\n @property({ type: String, attribute: 'label-dropzone' })\n labelDropzone = 'Drag files here or click to browse';\n\n /** Accessible label for the selected files list. */\n @property({ type: String, attribute: 'label-file-list' })\n labelFileList = 'Selected files';\n\n /**\n * Generates upload progress description for screen readers.\n * @param name - file name\n * @param progress - progress percentage 0-100\n */\n @property({ attribute: false })\n labelUploadProgress: (name: string, progress: number) => string = (name, progress) =>\n `Upload progress for ${name}: ${progress}%`;\n\n /**\n * Screen reader announcement when file drag detected. Override for i18n.\n * @attr label-drag-detected\n */\n @property({ attribute: 'label-drag-detected' })\n labelDragDetected = 'File detected. Release to upload.';\n\n // ─── Internal State ───\n\n /** The list of currently selected file entries, each with a file reference and upload progress. @internal */\n @state() private _files: FileEntry[] = [];\n /** Whether a file is currently being dragged over the dropzone. @internal */\n @state() private _dragOver = false;\n /** Whether the named file-list slot contains projected content. @internal */\n @state() private _hasFileListSlot = false;\n\n // ─── Internal References ───\n\n /** Reference to the hidden native file input element used to open the OS file picker. @internal */\n @query('.file-input')\n private _fileInput: HTMLInputElement | null | undefined;\n\n // ─── Stable IDs ───\n\n /** @internal */\n private readonly _baseId = `hx-file-upload-${++_hxFileUploadIdCounter}`;\n /** @internal */\n private readonly _labelId = `${this._baseId}-label`;\n /** @internal */\n private readonly _errorId = `${this._baseId}-error`;\n /** @internal */\n private readonly _dropzoneId = `${this._baseId}-dropzone`;\n /** @internal */\n private readonly _liveId = `${this._baseId}-live`;\n\n // ─── Slot Handling ───\n\n /** @internal */\n private _handleFileListSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFileListSlot = slot.assignedElements({ flatten: true }).length > 0;\n }\n\n // ─── Lifecycle ───\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('_files' as keyof HelixFileUpload) || changedProperties.has('name')) {\n this._syncFormValue();\n }\n }\n\n // ─── Form Integration ───\n\n /** Returns the associated form element, if any. */\n get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n\n /** Returns the validation message. */\n get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Returns the ValidityState object. */\n get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** Checks whether the component satisfies its constraints. */\n checkValidity(): boolean {\n return this._internals.checkValidity();\n }\n\n /** Reports validity and shows the browser's constraint validation UI. */\n reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n /** @internal */\n formResetCallback(): void {\n this._files = [];\n this._internals.setFormValue(null);\n }\n\n /** @internal */\n formDisabledCallback(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** @internal */\n formStateRestoreCallback(_state: string | File | FormData, mode: string): void {\n if (mode === 'restore' || mode === 'autocomplete') {\n this._files = [];\n this._internals.setFormValue(null);\n }\n }\n\n /** @internal */\n private _syncFormValue(): void {\n if (this._files.length === 0) {\n this._internals.setFormValue(null);\n return;\n }\n\n if (this._files.length === 1) {\n // Single file — pass directly as File (accepted by setFormValue)\n const firstEntry = this._files[0];\n if (firstEntry) {\n this._internals.setFormValue(firstEntry.file);\n }\n return;\n }\n\n // Multiple files — use FormData so all files are submitted under the same name\n const formData = new FormData();\n for (const entry of this._files) {\n formData.append(this.name, entry.file, entry.file.name);\n }\n this._internals.setFormValue(formData);\n }\n\n // ─── Validation ───\n\n /**\n * Validates a file against `accept` and `maxSize` constraints.\n * Returns null on success, or an error message string on failure.\n */\n /** @internal */\n private _validateFile(file: File): string | null {\n if (this.accept) {\n const accepted = this._isAccepted(file);\n if (!accepted) {\n return `\"${file.name}\" has an unsupported file type. Accepted types: ${this.accept}`;\n }\n }\n\n if (this.maxSize > 0 && file.size > this.maxSize) {\n const maxMb = (this.maxSize / (1024 * 1024)).toFixed(1);\n return `\"${file.name}\" exceeds the maximum size of ${maxMb} MB.`;\n }\n\n return null;\n }\n\n /**\n * Checks whether a file is accepted given the `accept` attribute value.\n * Handles MIME types (e.g. \"image/png\"), wildcard MIME types (e.g. \"image/*\"),\n * and extensions (e.g. \".pdf\").\n */\n /** @internal */\n private _isAccepted(file: File): boolean {\n const tokens = this.accept.split(',').map((t) => t.trim().toLowerCase());\n\n for (const token of tokens) {\n if (token.startsWith('.')) {\n // Extension match\n if (file.name.toLowerCase().endsWith(token)) return true;\n } else if (token.endsWith('/*')) {\n // Wildcard MIME type e.g. \"image/*\"\n const baseType = token.slice(0, -2);\n if (file.type.toLowerCase().startsWith(baseType)) return true;\n } else {\n // Exact MIME type\n if (file.type.toLowerCase() === token) return true;\n }\n }\n\n return false;\n }\n\n // ─── File Processing ───\n\n /** @internal */\n private _processFiles(rawFiles: File[]): void {\n if (this.disabled) return;\n\n const candidateFiles = this.multiple ? rawFiles : rawFiles.slice(0, 1);\n const validFiles: File[] = [];\n const invalidFiles: File[] = [];\n const errorMessages: string[] = [];\n\n for (const file of candidateFiles) {\n const validationError = this._validateFile(file);\n if (validationError) {\n invalidFiles.push(file);\n errorMessages.push(validationError);\n } else {\n validFiles.push(file);\n }\n }\n\n if (invalidFiles.length > 0) {\n this.dispatchEvent(\n new CustomEvent<{ message: string; files: File[] }>('hx-error', {\n bubbles: true,\n composed: true,\n detail: { message: errorMessages.join(' '), files: invalidFiles },\n }),\n );\n }\n\n if (validFiles.length === 0) return;\n\n // Enforce maxFiles limit (only in multiple mode — single-file mode always replaces)\n const currentCount = this.multiple ? this._files.length : 0;\n const capacity =\n this.maxFiles > 0 ? Math.max(0, this.maxFiles - currentCount) : validFiles.length;\n const allowedFiles = validFiles.slice(0, capacity);\n\n if (allowedFiles.length === 0 && this.maxFiles > 0) {\n this.dispatchEvent(\n new CustomEvent<{ message: string; files: File[] }>('hx-error', {\n bubbles: true,\n composed: true,\n detail: {\n message: `Maximum of ${this.maxFiles} file${this.maxFiles === 1 ? '' : 's'} allowed.`,\n files: validFiles,\n },\n }),\n );\n return;\n }\n\n if (allowedFiles.length > 0) {\n const newEntries: FileEntry[] = allowedFiles.map((file) => ({ file, progress: 0 }));\n\n if (this.multiple) {\n this._files = [...this._files, ...newEntries];\n } else {\n this._files = newEntries;\n }\n\n this.dispatchEvent(\n new CustomEvent<{ files: File[] }>('hx-upload', {\n bubbles: true,\n composed: true,\n detail: { files: allowedFiles },\n }),\n );\n }\n\n // If remaining valid files were cut by maxFiles, report that too\n const overflow = validFiles.slice(capacity);\n if (overflow.length > 0 && this.maxFiles > 0) {\n this.dispatchEvent(\n new CustomEvent<{ message: string; files: File[] }>('hx-error', {\n bubbles: true,\n composed: true,\n detail: {\n message: `Maximum of ${this.maxFiles} file${this.maxFiles === 1 ? '' : 's'} allowed. ${overflow.length} file${overflow.length === 1 ? ' was' : 's were'} not added.`,\n files: overflow,\n },\n }),\n );\n }\n }\n\n // ─── Public Methods ───\n\n /**\n * Sets the upload progress for a file at the given index.\n * @param index - Zero-based index into the current file list.\n * @param percent - Progress percentage from 0 to 100.\n */\n setProgress(index: number, percent: number): void {\n if (index < 0 || index >= this._files.length) return;\n const clamped = Math.max(0, Math.min(100, percent));\n this._files = this._files.map((entry, i) =>\n i === index ? { ...entry, progress: clamped } : entry,\n );\n }\n\n /**\n * Returns a read-only copy of the currently selected files.\n */\n get files(): File[] {\n return this._files.map((e) => e.file);\n }\n\n // ─── Drag and Drop Handlers ───\n\n /** @internal */\n private _handleDragOver(e: DragEvent): void {\n e.preventDefault();\n if (this.disabled) return;\n this._dragOver = true;\n }\n\n /** @internal */\n private _handleDragLeave(e: DragEvent): void {\n // Only clear drag state when leaving the dropzone entirely\n const target = e.relatedTarget as Node | null;\n if (target && this.contains(target)) return;\n const dropzone = this.shadowRoot?.querySelector('.dropzone');\n if (dropzone && dropzone.contains(target)) return;\n this._dragOver = false;\n }\n\n /** @internal */\n private _handleDrop(e: DragEvent): void {\n e.preventDefault();\n this._dragOver = false;\n if (this.disabled) return;\n\n const dt = e.dataTransfer;\n if (!dt) return;\n\n const rawFiles = Array.from(dt.files);\n if (rawFiles.length === 0) return;\n\n this._processFiles(rawFiles);\n }\n\n // ─── Click / Keyboard Handlers ───\n\n /** @internal */\n private _handleDropzoneClick(): void {\n if (this.disabled) return;\n this._fileInput?.click();\n }\n\n /** @internal */\n private _handleDropzoneKeyDown(e: KeyboardEvent): void {\n if (this.disabled) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this._fileInput?.click();\n }\n }\n\n /** @internal */\n private _handleFileInputChange(e: Event): void {\n const input = e.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n\n const rawFiles = Array.from(input.files);\n // Reset the input so the same file can be re-selected after removal\n input.value = '';\n this._processFiles(rawFiles);\n }\n\n // ─── Remove Handler ───\n\n /** @internal */\n private _handleRemove(index: number): void {\n if (this.disabled) return;\n const entry = this._files[index];\n if (!entry) return;\n\n const removedFile = entry.file;\n this._files = this._files.filter((_, i) => i !== index);\n\n this.dispatchEvent(\n new CustomEvent<{ file: File; index: number }>('hx-remove', {\n bubbles: true,\n composed: true,\n detail: { file: removedFile, index },\n }),\n );\n\n // Restore focus after removal so keyboard users are not stranded.\n this.updateComplete\n .then(() => {\n if (this._files.length === 0) {\n // List is now empty — return focus to the dropzone.\n const dropzone = this.shadowRoot?.querySelector<HTMLElement>('[part=\"dropzone\"]');\n dropzone?.focus();\n } else {\n // Focus the remove button at the same position, or the previous one if\n // the removed item was the last in the list.\n const removeButtons =\n this.shadowRoot?.querySelectorAll<HTMLButtonElement>('.file-item__remove');\n if (removeButtons && removeButtons.length > 0) {\n const targetIndex = index < this._files.length ? index : this._files.length - 1;\n const targetButton = removeButtons[targetIndex];\n if (targetButton) {\n targetButton.focus();\n }\n }\n }\n })\n .catch(() => {\n // Focus restoration is best-effort; ignore errors.\n });\n }\n\n // ─── Formatters ───\n\n /** @internal */\n private _formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderFileList() {\n if (this._hasFileListSlot) return nothing;\n if (this._files.length === 0) return nothing;\n\n return html`\n <ul part=\"file-list\" class=\"file-list\" aria-label=${this.labelFileList}>\n ${repeat(\n this._files,\n (entry) => entry.file.name + entry.file.size,\n (entry, index) => html`\n <li part=\"file-item\" class=\"file-item\">\n <div class=\"file-item__row\">\n <span class=\"file-item__name\" title=${entry.file.name}> ${entry.file.name} </span>\n <span class=\"file-item__size\">${this._formatSize(entry.file.size)}</span>\n <button\n type=\"button\"\n class=\"file-item__remove\"\n aria-label=${`Remove ${entry.file.name}`}\n @click=${() => this._handleRemove(index)}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path\n d=\"M1 1L13 13M13 1L1 13\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </div>\n <div\n part=\"progress\"\n class=\"progress-track\"\n role=\"progressbar\"\n aria-valuenow=${entry.progress}\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n aria-label=${this.labelUploadProgress(entry.file.name, entry.progress)}\n >\n <div\n class=\"progress-bar\"\n style=\"--_progress-ratio: ${String(entry.progress / 100)}\"\n ></div>\n </div>\n </li>\n `,\n )}\n </ul>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const hasError = !!this.error;\n\n const dropzoneClasses = {\n dropzone: true,\n 'dropzone--drag-over': this._dragOver,\n 'dropzone--error': hasError,\n };\n\n const dropzoneLabel = this.label ? `${this.label} — ${this.labelDropzone}` : this.labelDropzone;\n\n return html`\n <div class=\"field\">\n ${this.label\n ? html`\n <label part=\"label\" class=\"field__label\" id=${this._labelId} for=${this._dropzoneId}>\n ${this.label}\n </label>\n `\n : nothing}\n\n <div\n part=\"dropzone\"\n class=${classMap(dropzoneClasses)}\n id=${this._dropzoneId}\n role=\"button\"\n tabindex=${this.disabled ? '-1' : '0'}\n aria-label=${ifDefined(!this.label ? (this.ariaLabel ?? dropzoneLabel) : undefined)}\n aria-labelledby=${ifDefined(this.label ? this._labelId : undefined)}\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(hasError ? this._errorId : undefined)}\n @click=${this._handleDropzoneClick}\n @keydown=${this._handleDropzoneKeyDown}\n @dragover=${this._handleDragOver}\n @dragleave=${this._handleDragLeave}\n @drop=${this._handleDrop}\n >\n <slot>${this.labelDropzone}</slot>\n </div>\n\n <input\n class=\"file-input\"\n type=\"file\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n accept=${ifDefined(this.accept || undefined)}\n ?multiple=${this.multiple}\n ?disabled=${this.disabled}\n @change=${this._handleFileInputChange}\n />\n\n <slot name=\"file-list\" @slotchange=${this._handleFileListSlotChange}></slot>\n\n ${this._renderFileList()}\n ${hasError\n ? html`\n <div part=\"error\" class=\"field__error\" id=${this._errorId} role=\"alert\">\n ${this.error}\n </div>\n `\n : nothing}\n\n <div id=${this._liveId} class=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n ${this._dragOver ? this.labelDragDetected : ''}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-file-upload': HelixFileUpload;\n }\n}\n"],"names":["helixFileUploadStyles","css","_hxFileUploadIdCounter","HelixFileUpload","mixinDelegatesAria","LitElement","name","progress","slot","changedProperties","disabled","_state","mode","firstEntry","formData","entry","file","maxMb","tokens","token","baseType","rawFiles","candidateFiles","validFiles","invalidFiles","errorMessages","validationError","currentCount","capacity","allowedFiles","newEntries","overflow","index","percent","clamped","i","target","dropzone","_a","dt","input","removedFile","_","removeButtons","_b","targetIndex","targetButton","bytes","nothing","html","repeat","hasError","dropzoneClasses","dropzoneLabel","classMap","ifDefined","__decorateClass","property","state","query","customElement"],"mappings":";;;;;;;AAEO,MAAMA,IAAwBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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"}
@@ -207,13 +207,7 @@ let i = class extends m {
207
207
  // ─── Render ───
208
208
  render() {
209
209
  const e = this._validationErrors.length > 0 ? c`
210
- <div
211
- class="hx-form-error-summary"
212
- role="alert"
213
- aria-live="assertive"
214
- aria-atomic="true"
215
- tabindex="-1"
216
- >
210
+ <div class="hx-form-error-summary" role="alert" aria-atomic="true" tabindex="-1">
217
211
  <ul>
218
212
  ${this._validationErrors.map(
219
213
  (r) => c`<li>${r.message || r.name}</li>`
@@ -259,4 +253,4 @@ i = s([
259
253
  export {
260
254
  i as H
261
255
  };
262
- //# sourceMappingURL=hx-form-fJE-FJQV.js.map
256
+ //# sourceMappingURL=hx-form-BM6PHsw3.js.map