@compa11y/web 0.1.0 → 0.1.2

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 (38) hide show
  1. package/README.md +608 -0
  2. package/dist/compa11y.iife.js +1126 -26
  3. package/dist/compa11y.iife.js.map +1 -1
  4. package/dist/compa11y.js +3671 -715
  5. package/dist/compa11y.js.map +1 -1
  6. package/dist/compa11y.umd.cjs +1129 -29
  7. package/dist/compa11y.umd.cjs.map +1 -1
  8. package/dist/components/button.d.ts +32 -0
  9. package/dist/components/button.d.ts.map +1 -0
  10. package/dist/components/checkbox.d.ts +160 -0
  11. package/dist/components/checkbox.d.ts.map +1 -0
  12. package/dist/components/combobox.d.ts +2 -2
  13. package/dist/components/combobox.d.ts.map +1 -1
  14. package/dist/components/dialog.d.ts +2 -2
  15. package/dist/components/dialog.d.ts.map +1 -1
  16. package/dist/components/input.d.ts +41 -0
  17. package/dist/components/input.d.ts.map +1 -0
  18. package/dist/components/listbox.d.ts +86 -0
  19. package/dist/components/listbox.d.ts.map +1 -0
  20. package/dist/components/menu.d.ts +2 -2
  21. package/dist/components/menu.d.ts.map +1 -1
  22. package/dist/components/radio-group.d.ts +87 -0
  23. package/dist/components/radio-group.d.ts.map +1 -0
  24. package/dist/components/select.d.ts +47 -0
  25. package/dist/components/select.d.ts.map +1 -0
  26. package/dist/components/switch.d.ts +2 -2
  27. package/dist/components/switch.d.ts.map +1 -1
  28. package/dist/components/tabs.d.ts +2 -2
  29. package/dist/components/tabs.d.ts.map +1 -1
  30. package/dist/components/textarea.d.ts +41 -0
  31. package/dist/components/textarea.d.ts.map +1 -0
  32. package/dist/index.d.ts +8 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/utils/base-element.d.ts +1 -1
  35. package/dist/utils/base-element.d.ts.map +1 -1
  36. package/dist/utils/styles.d.ts +44 -0
  37. package/dist/utils/styles.d.ts.map +1 -1
  38. package/package.json +39 -3
package/dist/compa11y.js CHANGED
@@ -1,8 +1,8 @@
1
- import { generateId as E, announce as r, announcePolite as g, prefersDarkMode as k, prefersHighContrast as A, prefersReducedMotion as I, isBrowser as L, hasAccessibleName as S, buildAriaProps as C, aria as $, createTypeAhead as T, KeyboardPatterns as D, createKeyboardManager as O, createRovingTabindex as z, createFocusScope as q, createFocusTrap as M, initFocusVisible as p, announceError as R, announceStatus as H, announceAssertive as V, initAnnouncer as b } from "@compa11y/core";
2
- import { KeyboardPatterns as G, announce as W, announceAssertive as J, announceError as Q, announcePolite as Z, announceStatus as tt, aria as et, buildAriaProps as it, createFocusScope as st, createFocusTrap as ot, createKeyboardManager as at, createRovingTabindex as nt, createTypeAhead as lt, hasAccessibleName as rt, initAnnouncer as ht, initFocusVisible as dt, isBrowser as ct, prefersDarkMode as ut, prefersHighContrast as pt, prefersReducedMotion as bt } from "@compa11y/core";
3
- class h extends HTMLElement {
1
+ import { generateId as te, announce as v, announcePolite as p, createTypeAhead as q, announceAssertive as D, prefersDarkMode as ie, prefersHighContrast as se, prefersReducedMotion as ae, isBrowser as re, hasAccessibleName as oe, buildAriaProps as le, aria as ne, KeyboardPatterns as he, createKeyboardManager as de, createRovingTabindex as ce, createFocusScope as ue, createFocusTrap as be, initFocusVisible as T, announceError as pe, announceStatus as ge, initAnnouncer as R } from "@compa11y/core";
2
+ import { KeyboardPatterns as He, announce as Me, announceAssertive as Ke, announceError as Fe, announcePolite as Ne, announceStatus as Pe, aria as je, buildAriaProps as Ue, createFocusScope as Ye, createFocusTrap as Ge, createKeyboardManager as Xe, createRovingTabindex as Ve, createTypeAhead as We, hasAccessibleName as Je, initAnnouncer as Qe, initFocusVisible as Ze, isBrowser as et, prefersDarkMode as tt, prefersHighContrast as it, prefersReducedMotion as st } from "@compa11y/core";
3
+ class c extends HTMLElement {
4
4
  constructor() {
5
- super(), this._internals = null, this._id = E(this.tagName.toLowerCase().replace("a11y-", "")), "attachInternals" in this && (this._internals = this.attachInternals());
5
+ super(), this._internals = null, this._id = te(this.tagName.toLowerCase().replace("a11y-", "")), "attachInternals" in this && (this._internals = this.attachInternals());
6
6
  }
7
7
  /**
8
8
  * Standard observed attributes
@@ -25,8 +25,8 @@ class h extends HTMLElement {
25
25
  /**
26
26
  * Called when observed attributes change
27
27
  */
28
- attributeChangedCallback(t, e, i) {
29
- e !== i && this.onAttributeChange(t, e, i);
28
+ attributeChangedCallback(e, t, i) {
29
+ t !== i && this.onAttributeChange(e, t, i);
30
30
  }
31
31
  /**
32
32
  * Set up event listeners
@@ -41,15 +41,15 @@ class h extends HTMLElement {
41
41
  /**
42
42
  * Handle attribute changes
43
43
  */
44
- onAttributeChange(t, e, i) {
44
+ onAttributeChange(e, t, i) {
45
45
  }
46
46
  /**
47
47
  * Emit a custom event
48
48
  */
49
- emit(t, e) {
49
+ emit(e, t) {
50
50
  return this.dispatchEvent(
51
- new CustomEvent(t, {
52
- detail: e,
51
+ new CustomEvent(e, {
52
+ detail: t,
53
53
  bubbles: !0,
54
54
  composed: !0,
55
55
  cancelable: !0
@@ -59,25 +59,25 @@ class h extends HTMLElement {
59
59
  /**
60
60
  * Query a slot
61
61
  */
62
- getSlot(t) {
63
- var e;
64
- return ((e = this.shadowRoot) == null ? void 0 : e.querySelector(`slot[name="${t}"]`)) ?? null;
62
+ getSlot(e) {
63
+ var t;
64
+ return ((t = this.shadowRoot) == null ? void 0 : t.querySelector(`slot[name="${e}"]`)) ?? null;
65
65
  }
66
66
  /**
67
67
  * Get slotted elements
68
68
  */
69
- getSlottedElements(t) {
69
+ getSlottedElements(e) {
70
70
  var s;
71
- const e = t ? `slot[name="${t}"]` : "slot:not([name])", i = (s = this.shadowRoot) == null ? void 0 : s.querySelector(
72
- e
71
+ const t = e ? `slot[name="${e}"]` : "slot:not([name])", i = (s = this.shadowRoot) == null ? void 0 : s.querySelector(
72
+ t
73
73
  );
74
74
  return (i == null ? void 0 : i.assignedElements()) ?? [];
75
75
  }
76
76
  }
77
- function d(n, t) {
78
- customElements.get(n) || customElements.define(n, t);
77
+ function u(n, e) {
78
+ customElements.get(n) || customElements.define(n, e);
79
79
  }
80
- const f = `
80
+ const H = `
81
81
  appearance: none;
82
82
  background: none;
83
83
  border: none;
@@ -86,13 +86,13 @@ const f = `
86
86
  font: inherit;
87
87
  color: inherit;
88
88
  cursor: pointer;
89
- `, K = `
89
+ `, me = `
90
90
  :host(:focus-visible),
91
91
  :focus-visible {
92
92
  outline: 2px solid var(--compa11y-focus-color, #0066cc);
93
93
  outline-offset: 2px;
94
94
  }
95
- `, c = `
95
+ `, b = `
96
96
  :host {
97
97
  display: block;
98
98
  box-sizing: border-box;
@@ -108,9 +108,9 @@ const f = `
108
108
  box-sizing: inherit;
109
109
  }
110
110
 
111
- ${K}
112
- `, B = `
113
- ${c}
111
+ ${me}
112
+ `, ve = `
113
+ ${b}
114
114
 
115
115
  :host {
116
116
  position: fixed;
@@ -148,8 +148,8 @@ const f = `
148
148
  margin: 0 0 1rem 0;
149
149
  color: var(--compa11y-dialog-description-color, #666);
150
150
  }
151
- `, F = `
152
- ${c}
151
+ `, fe = `
152
+ ${b}
153
153
 
154
154
  :host {
155
155
  position: relative;
@@ -200,8 +200,8 @@ const f = `
200
200
  margin: 0.25rem 0;
201
201
  background: var(--compa11y-menu-separator-color, #e0e0e0);
202
202
  }
203
- `, P = `
204
- ${c}
203
+ `, _e = `
204
+ ${b}
205
205
 
206
206
  .tablist {
207
207
  display: flex;
@@ -216,7 +216,7 @@ const f = `
216
216
  }
217
217
 
218
218
  ::slotted([role="tab"]) {
219
- ${f}
219
+ ${H}
220
220
  padding: var(--compa11y-tab-padding, 0.75rem 1rem);
221
221
  border-bottom: 2px solid transparent;
222
222
  margin-bottom: -1px;
@@ -246,8 +246,8 @@ const f = `
246
246
  ::slotted([role="tabpanel"][hidden]) {
247
247
  display: none;
248
248
  }
249
- `, N = `
250
- ${c}
249
+ `, ye = `
250
+ ${b}
251
251
 
252
252
  :host {
253
253
  display: inline-block;
@@ -305,7 +305,7 @@ const f = `
305
305
  }
306
306
 
307
307
  .clear-button {
308
- ${f}
308
+ ${H}
309
309
  position: absolute;
310
310
  right: 1.5rem;
311
311
  width: 1.25rem;
@@ -387,8 +387,138 @@ const f = `
387
387
  .options-source {
388
388
  display: none;
389
389
  }
390
- `, U = `
391
- ${c}
390
+ `, xe = `
391
+ ${b}
392
+
393
+ :host {
394
+ display: inline-block;
395
+ position: relative;
396
+ width: var(--compa11y-select-width, 250px);
397
+ }
398
+
399
+ .select-wrapper {
400
+ position: relative;
401
+ }
402
+
403
+ .select-trigger {
404
+ width: 100%;
405
+ display: flex;
406
+ align-items: center;
407
+ justify-content: space-between;
408
+ padding: var(--compa11y-select-trigger-padding, 0.5rem 2rem 0.5rem 0.75rem);
409
+ border: var(--compa11y-select-border, 1px solid #ccc);
410
+ border-radius: var(--compa11y-select-radius, 4px);
411
+ font: inherit;
412
+ background: var(--compa11y-select-bg, white);
413
+ color: var(--compa11y-select-color, inherit);
414
+ cursor: pointer;
415
+ text-align: left;
416
+ position: relative;
417
+ appearance: none;
418
+ }
419
+
420
+ .select-trigger:focus {
421
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
422
+ outline-offset: -1px;
423
+ border-color: var(--compa11y-focus-color, #0066cc);
424
+ }
425
+
426
+ .select-trigger:disabled {
427
+ background: var(--compa11y-select-disabled-bg, #f5f5f5);
428
+ cursor: not-allowed;
429
+ opacity: 0.7;
430
+ }
431
+
432
+ .select-value {
433
+ flex: 1;
434
+ overflow: hidden;
435
+ text-overflow: ellipsis;
436
+ white-space: nowrap;
437
+ }
438
+
439
+ .select-value.placeholder {
440
+ color: var(--compa11y-select-placeholder-color, #999);
441
+ }
442
+
443
+ .chevron {
444
+ position: absolute;
445
+ right: 0.5rem;
446
+ pointer-events: none;
447
+ font-size: 0.75rem;
448
+ color: var(--compa11y-select-chevron-color, #666);
449
+ transition: transform 0.15s ease;
450
+ }
451
+
452
+ :host([open]) .chevron {
453
+ transform: rotate(180deg);
454
+ }
455
+
456
+ :host([data-position="top"]) .chevron {
457
+ transform: rotate(180deg);
458
+ }
459
+
460
+ :host([data-position="top"][open]) .chevron {
461
+ transform: rotate(0deg);
462
+ }
463
+
464
+ .listbox {
465
+ position: absolute;
466
+ top: 100%;
467
+ left: 0;
468
+ right: 0;
469
+ z-index: var(--compa11y-select-z-index, 1000);
470
+ max-height: var(--compa11y-select-max-height, 200px);
471
+ overflow-y: auto;
472
+ margin: 0;
473
+ padding: var(--compa11y-select-listbox-padding, 0.25rem 0);
474
+ background: var(--compa11y-select-listbox-bg, white);
475
+ border: var(--compa11y-select-listbox-border, 1px solid #e0e0e0);
476
+ border-radius: var(--compa11y-select-radius, 4px);
477
+ box-shadow: var(--compa11y-select-shadow, 0 4px 6px -1px rgba(0, 0, 0, 0.1));
478
+ list-style: none;
479
+ margin-top: 4px;
480
+ }
481
+
482
+ .listbox[hidden] {
483
+ display: none;
484
+ }
485
+
486
+ .listbox li[role="option"] {
487
+ display: flex;
488
+ align-items: center;
489
+ justify-content: space-between;
490
+ padding: var(--compa11y-select-option-padding, 0.5rem 0.75rem);
491
+ cursor: pointer;
492
+ transition: background 0.1s ease;
493
+ }
494
+
495
+ .listbox li[role="option"]:hover,
496
+ .listbox li[role="option"].highlighted {
497
+ background: var(--compa11y-select-option-hover-bg, #f5f5f5);
498
+ }
499
+
500
+ .listbox li[role="option"][aria-selected="true"] {
501
+ background: var(--compa11y-select-option-selected-bg, #e6f0ff);
502
+ font-weight: 500;
503
+ }
504
+
505
+ .listbox li[role="option"].disabled,
506
+ .listbox li[role="option"][aria-disabled="true"] {
507
+ opacity: 0.5;
508
+ cursor: not-allowed;
509
+ }
510
+
511
+ .check-mark {
512
+ font-size: 0.875rem;
513
+ color: var(--compa11y-select-check-color, #0066cc);
514
+ margin-left: 0.5rem;
515
+ }
516
+
517
+ .options-source {
518
+ display: none;
519
+ }
520
+ `, Ae = `
521
+ ${b}
392
522
 
393
523
  :host {
394
524
  display: inline-block;
@@ -491,669 +621,2926 @@ const f = `
491
621
  opacity: 0.5;
492
622
  cursor: not-allowed;
493
623
  }
494
- `, m = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
495
- class y extends h {
496
- constructor() {
497
- super(...arguments), this._open = !1, this._previouslyFocused = null, this._triggerElement = null, this.handleTriggerClick = () => {
498
- this.open = !0;
499
- }, this.handleClose = () => {
500
- this.open = !1;
501
- }, this.handleKeyDown = (t) => {
502
- var e;
503
- if (this._open) {
504
- if (t.key === "Escape") {
505
- this.getAttribute("close-on-escape") !== "false" && (t.preventDefault(), this.handleClose());
506
- return;
507
- }
508
- if (t.key === "Tab") {
509
- t.preventDefault();
510
- const i = this.getFocusableElements();
511
- if (i.length === 0) return;
512
- const s = ((e = this.shadowRoot) == null ? void 0 : e.activeElement) || document.activeElement;
513
- let o = i.findIndex(
514
- (u) => u === s
515
- );
516
- o === -1 && (o = t.shiftKey ? 0 : i.length - 1);
517
- let a;
518
- t.shiftKey ? a = o === 0 ? i.length - 1 : o - 1 : a = o === i.length - 1 ? 0 : o + 1;
519
- const l = i[a];
520
- l && l.focus();
521
- }
522
- }
523
- };
624
+ `, Ee = `
625
+ ${b}
626
+
627
+ :host {
628
+ display: block;
629
+ width: var(--compa11y-input-width, 100%);
524
630
  }
525
- static get observedAttributes() {
526
- return ["open", "trigger", "close-on-outside-click", "close-on-escape"];
631
+
632
+ .input-wrapper {
633
+ display: flex;
634
+ flex-direction: column;
635
+ gap: 0.25rem;
527
636
  }
528
- get open() {
529
- return this._open;
637
+
638
+ .input-label {
639
+ display: block;
640
+ color: var(--compa11y-input-label-color, inherit);
641
+ font-size: var(--compa11y-input-label-size, 0.875rem);
642
+ font-weight: var(--compa11y-input-label-weight, 500);
530
643
  }
531
- set open(t) {
532
- const e = this._open;
533
- this._open = t, t !== e && (t ? this.showDialog() : this.hideDialog()), this.toggleAttribute("open", t);
644
+
645
+ :host([disabled]) .input-label {
646
+ color: var(--compa11y-input-disabled-color, #999);
534
647
  }
535
- setupAccessibility() {
648
+
649
+ .input-required {
650
+ color: var(--compa11y-input-required-color, #ef4444);
651
+ margin-left: 0.125rem;
536
652
  }
537
- render() {
538
- const t = this.attachShadow({ mode: "open" }), e = `${this._id}-title`, i = `${this._id}-desc`;
539
- t.innerHTML = `
540
- <style>${B}</style>
541
- <div class="overlay" part="overlay"></div>
542
- <div
543
- class="dialog"
544
- role="dialog"
545
- aria-modal="true"
546
- aria-labelledby="${e}"
547
- aria-describedby="${i}"
548
- part="dialog"
549
- >
550
- <div id="${e}" part="title">
551
- <slot name="title"></slot>
552
- </div>
553
- <div id="${i}" part="description">
554
- <slot name="description"></slot>
555
- </div>
556
- <div part="content">
557
- <slot></slot>
558
- </div>
559
- <div part="actions">
560
- <slot name="actions"></slot>
561
- </div>
562
- </div>
563
- `, this._open || (this.style.display = "none");
653
+
654
+ input {
655
+ width: 100%;
656
+ padding: var(--compa11y-input-padding, 0.5rem 0.75rem);
657
+ border: var(--compa11y-input-border, 1px solid #ccc);
658
+ border-radius: var(--compa11y-input-radius, 4px);
659
+ font: inherit;
660
+ font-size: var(--compa11y-input-font-size, 0.875rem);
661
+ background: var(--compa11y-input-bg, white);
662
+ color: inherit;
564
663
  }
565
- setupEventListeners() {
566
- var i;
567
- const t = this.getAttribute("trigger");
568
- if (t) {
569
- const s = () => {
570
- this._triggerElement = document.querySelector(t), this._triggerElement && (this._triggerElement.addEventListener(
571
- "click",
572
- this.handleTriggerClick
573
- ), this._triggerElement.hasAttribute("tabindex") || this._triggerElement.setAttribute("tabindex", "0"));
574
- };
575
- s(), this._triggerElement || requestAnimationFrame(() => {
576
- s(), this._triggerElement || setTimeout(s, 0);
577
- });
578
- }
579
- const e = (i = this.shadowRoot) == null ? void 0 : i.querySelector(".overlay");
580
- this.getAttribute("close-on-outside-click") !== "false" && (e == null || e.addEventListener("click", this.handleClose)), this.addEventListener("keydown", this.handleKeyDown);
664
+
665
+ input:focus {
666
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
667
+ outline-offset: -1px;
668
+ border-color: var(--compa11y-input-border-focus, #0066cc);
581
669
  }
582
- cleanupEventListeners() {
583
- var t;
584
- (t = this._triggerElement) == null || t.removeEventListener("click", this.handleTriggerClick), this.removeEventListener("keydown", this.handleKeyDown);
670
+
671
+ input::placeholder {
672
+ color: var(--compa11y-input-placeholder-color, #999);
585
673
  }
586
- onAttributeChange(t, e, i) {
587
- t === "open" && (this.open = i !== null);
674
+
675
+ input:disabled {
676
+ background: var(--compa11y-input-disabled-bg, #f5f5f5);
677
+ cursor: not-allowed;
678
+ opacity: var(--compa11y-input-disabled-opacity, 0.7);
588
679
  }
589
- /**
590
- * Get all focusable elements in the dialog (light DOM first, then shadow DOM)
591
- * Per WAI-ARIA best practices: focus should go to dialog content first,
592
- * close button should be last in tab order
593
- */
594
- getFocusableElements() {
595
- const t = [];
596
- return this.querySelectorAll(m).forEach((i) => t.push(i)), this.shadowRoot && this.shadowRoot.querySelectorAll(m).forEach((s) => {
597
- s.classList.contains("overlay") || t.push(s);
598
- }), t;
680
+
681
+ input[readonly] {
682
+ background: var(--compa11y-input-readonly-bg, #f9f9f9);
599
683
  }
600
- showDialog() {
601
- this._previouslyFocused = document.activeElement, this.style.display = "flex", requestAnimationFrame(() => {
602
- const e = this.getFocusableElements()[0];
603
- e && e.focus();
604
- }), document.body.style.overflow = "hidden", r("Dialog opened", { politeness: "polite" }), this.emit("a11y-dialog-open");
684
+
685
+ :host([data-error="true"]) input {
686
+ border-color: var(--compa11y-input-border-error, #ef4444);
605
687
  }
606
- hideDialog() {
607
- var t;
608
- this.style.display = "none", document.body.style.overflow = "", (t = this._previouslyFocused) == null || t.focus(), this._previouslyFocused = null, r("Dialog closed", { politeness: "polite" }), this.emit("a11y-dialog-close");
688
+
689
+ :host([data-error="true"]) input:focus {
690
+ outline-color: var(--compa11y-input-border-error, #ef4444);
691
+ border-color: var(--compa11y-input-border-error, #ef4444);
609
692
  }
610
- /**
611
- * Programmatic open
612
- */
613
- show() {
614
- this.open = !0;
693
+
694
+ .input-hint {
695
+ color: var(--compa11y-input-hint-color, #666);
696
+ font-size: var(--compa11y-input-hint-size, 0.8125rem);
615
697
  }
616
- /**
617
- * Programmatic close
618
- */
619
- close() {
620
- this.open = !1;
698
+
699
+ .input-error {
700
+ color: var(--compa11y-input-error-color, #ef4444);
701
+ font-size: var(--compa11y-input-error-size, 0.8125rem);
621
702
  }
622
- }
623
- d("a11y-dialog", y);
624
- class _ extends h {
625
- constructor() {
626
- super(...arguments), this._open = !1, this._highlightedIndex = -1, this._menuItems = [], this.updateMenuItems = () => {
627
- this._menuItems = Array.from(
628
- this.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')
629
- ), this._menuItems.forEach((t, e) => {
630
- t.id = t.id || `${this._id}-item-${e}`, t.setAttribute("tabindex", "-1");
631
- });
632
- }, this._lastClickTime = 0, this.handleTriggerClick = () => {
633
- const t = Date.now();
634
- t - this._lastClickTime < 50 || (this._lastClickTime = t, this.toggle());
635
- }, this.handleTriggerKeyDown = (t) => {
636
- switch (t.key) {
637
- case "Enter":
638
- case " ":
639
- t.preventDefault(), this.toggle(), this._open && this.highlightItem(0);
640
- break;
641
- case "ArrowDown":
642
- t.preventDefault(), this._open || this.show(), this.highlightItem(0);
643
- break;
644
- case "ArrowUp":
645
- t.preventDefault(), this._open || this.show(), this.highlightItem(this._menuItems.length - 1);
646
- break;
647
- }
648
- }, this.handleMenuKeyDown = (t) => {
649
- if (!this._open) return;
650
- const e = t.target;
651
- if (!(!e.hasAttribute("role") || e.getAttribute("role") !== "menuitem"))
652
- switch (t.key) {
653
- case "ArrowDown":
654
- t.preventDefault(), this.highlightItem(
655
- (this._highlightedIndex + 1) % this._menuItems.length
656
- );
657
- break;
658
- case "ArrowUp":
659
- t.preventDefault(), this.highlightItem(
660
- (this._highlightedIndex - 1 + this._menuItems.length) % this._menuItems.length
661
- );
662
- break;
663
- case "Home":
664
- t.preventDefault(), this.highlightItem(0);
665
- break;
666
- case "End":
667
- t.preventDefault(), this.highlightItem(this._menuItems.length - 1);
668
- break;
669
- case "Enter":
670
- case " ":
671
- t.preventDefault(), this.selectItem(this._highlightedIndex);
672
- break;
673
- case "Escape":
674
- t.preventDefault(), this.close();
675
- break;
676
- case "Tab":
677
- this.close();
678
- break;
679
- }
680
- }, this.handleItemClick = (t) => {
681
- const e = t.target;
682
- if (e.getAttribute("role") === "menuitem" && e.getAttribute("aria-disabled") !== "true") {
683
- const i = this._menuItems.indexOf(e);
684
- this.selectItem(i);
685
- }
686
- }, this.handleMouseOver = (t) => {
687
- const e = t.target;
688
- if (e.getAttribute("role") === "menuitem") {
689
- const i = this._menuItems.indexOf(e);
690
- i !== -1 && this.highlightItem(i, !1);
691
- }
692
- }, this.handleOutsideClick = (t) => {
693
- if (!this._open) return;
694
- t.composedPath().includes(this) || this.close();
695
- };
703
+ `, ke = `
704
+ ${b}
705
+
706
+ :host {
707
+ display: block;
708
+ width: var(--compa11y-textarea-width, 100%);
696
709
  }
697
- static get observedAttributes() {
698
- return ["open"];
710
+
711
+ .textarea-wrapper {
712
+ display: flex;
713
+ flex-direction: column;
714
+ gap: 0.25rem;
699
715
  }
700
- get open() {
701
- return this._open;
716
+
717
+ .textarea-label {
718
+ display: block;
719
+ color: var(--compa11y-textarea-label-color, inherit);
720
+ font-size: var(--compa11y-textarea-label-size, 0.875rem);
721
+ font-weight: var(--compa11y-textarea-label-weight, 500);
702
722
  }
703
- set open(t) {
704
- const e = this._open;
705
- this._open = t, t !== e && this.updateMenuVisibility(), this.toggleAttribute("open", t);
723
+
724
+ :host([disabled]) .textarea-label {
725
+ color: var(--compa11y-textarea-disabled-color, #999);
706
726
  }
707
- setupAccessibility() {
708
- const t = this.querySelector('[slot="trigger"]');
709
- t && (t.setAttribute("aria-haspopup", "menu"), t.setAttribute("aria-expanded", String(this._open)), t.id = t.id || `${this._id}-trigger`, t.hasAttribute("tabindex") || t.setAttribute("tabindex", "0"));
727
+
728
+ .textarea-required {
729
+ color: var(--compa11y-textarea-required-color, #ef4444);
730
+ margin-left: 0.125rem;
731
+ }
732
+
733
+ textarea {
734
+ width: 100%;
735
+ padding: var(--compa11y-textarea-padding, 0.5rem 0.75rem);
736
+ border: var(--compa11y-textarea-border, 1px solid #ccc);
737
+ border-radius: var(--compa11y-textarea-radius, 4px);
738
+ font: inherit;
739
+ font-size: var(--compa11y-textarea-font-size, 0.875rem);
740
+ line-height: 1.5;
741
+ background: var(--compa11y-textarea-bg, white);
742
+ color: inherit;
743
+ resize: var(--compa11y-textarea-resize, vertical);
744
+ }
745
+
746
+ textarea:focus {
747
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
748
+ outline-offset: -1px;
749
+ border-color: var(--compa11y-textarea-border-focus, #0066cc);
750
+ }
751
+
752
+ textarea::placeholder {
753
+ color: var(--compa11y-textarea-placeholder-color, #999);
754
+ }
755
+
756
+ textarea:disabled {
757
+ background: var(--compa11y-textarea-disabled-bg, #f5f5f5);
758
+ cursor: not-allowed;
759
+ opacity: var(--compa11y-textarea-disabled-opacity, 0.7);
760
+ }
761
+
762
+ textarea[readonly] {
763
+ background: var(--compa11y-textarea-readonly-bg, #f9f9f9);
764
+ }
765
+
766
+ :host([data-error="true"]) textarea {
767
+ border-color: var(--compa11y-textarea-border-error, #ef4444);
768
+ }
769
+
770
+ :host([data-error="true"]) textarea:focus {
771
+ outline-color: var(--compa11y-textarea-border-error, #ef4444);
772
+ border-color: var(--compa11y-textarea-border-error, #ef4444);
773
+ }
774
+
775
+ .textarea-hint {
776
+ color: var(--compa11y-textarea-hint-color, #666);
777
+ font-size: var(--compa11y-textarea-hint-size, 0.8125rem);
778
+ }
779
+
780
+ .textarea-error {
781
+ color: var(--compa11y-textarea-error-color, #ef4444);
782
+ font-size: var(--compa11y-textarea-error-size, 0.8125rem);
783
+ }
784
+ `, we = `
785
+ ${b}
786
+
787
+ :host {
788
+ display: inline-block;
789
+ }
790
+
791
+ @keyframes compa11y-spin {
792
+ to { transform: rotate(360deg); }
793
+ }
794
+
795
+ button {
796
+ display: inline-flex;
797
+ align-items: center;
798
+ justify-content: center;
799
+ gap: 0.5rem;
800
+ border-radius: var(--compa11y-button-radius, 4px);
801
+ font: inherit;
802
+ font-weight: var(--compa11y-button-font-weight, 500);
803
+ line-height: 1.5;
804
+ cursor: pointer;
805
+ transition: background-color 0.15s ease, border-color 0.15s ease;
806
+ appearance: none;
807
+ text-decoration: none;
808
+ }
809
+
810
+ button:focus-visible {
811
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
812
+ outline-offset: 2px;
813
+ }
814
+
815
+ /* Sizes */
816
+ button.size-sm {
817
+ padding: var(--compa11y-button-padding-sm, 0.25rem 0.5rem);
818
+ font-size: var(--compa11y-button-font-size-sm, 0.75rem);
819
+ }
820
+
821
+ button.size-md {
822
+ padding: var(--compa11y-button-padding-md, 0.5rem 1rem);
823
+ font-size: var(--compa11y-button-font-size-md, 0.875rem);
824
+ }
825
+
826
+ button.size-lg {
827
+ padding: var(--compa11y-button-padding-lg, 0.75rem 1.5rem);
828
+ font-size: var(--compa11y-button-font-size-lg, 1rem);
829
+ }
830
+
831
+ /* Variants */
832
+ button.variant-primary {
833
+ background: var(--compa11y-button-primary-bg, #0066cc);
834
+ color: var(--compa11y-button-primary-color, white);
835
+ border: var(--compa11y-button-primary-border, 1px solid #0066cc);
836
+ }
837
+
838
+ button.variant-primary:hover:not(:disabled):not([aria-disabled="true"]) {
839
+ background: var(--compa11y-button-primary-hover-bg, #0052a3);
840
+ }
841
+
842
+ button.variant-secondary {
843
+ background: var(--compa11y-button-secondary-bg, white);
844
+ color: var(--compa11y-button-secondary-color, #333);
845
+ border: var(--compa11y-button-secondary-border, 1px solid #ccc);
846
+ }
847
+
848
+ button.variant-secondary:hover:not(:disabled):not([aria-disabled="true"]) {
849
+ background: var(--compa11y-button-secondary-hover-bg, #f0f0f0);
850
+ }
851
+
852
+ button.variant-danger {
853
+ background: var(--compa11y-button-danger-bg, #ef4444);
854
+ color: var(--compa11y-button-danger-color, white);
855
+ border: var(--compa11y-button-danger-border, 1px solid #ef4444);
856
+ }
857
+
858
+ button.variant-danger:hover:not(:disabled):not([aria-disabled="true"]) {
859
+ background: var(--compa11y-button-danger-hover-bg, #dc2626);
860
+ }
861
+
862
+ button.variant-outline {
863
+ background: var(--compa11y-button-outline-bg, transparent);
864
+ color: var(--compa11y-button-outline-color, #0066cc);
865
+ border: var(--compa11y-button-outline-border, 1px solid #0066cc);
866
+ }
867
+
868
+ button.variant-outline:hover:not(:disabled):not([aria-disabled="true"]) {
869
+ background: var(--compa11y-button-outline-hover-bg, rgba(0, 102, 204, 0.05));
870
+ }
871
+
872
+ button.variant-ghost {
873
+ background: var(--compa11y-button-ghost-bg, transparent);
874
+ color: var(--compa11y-button-ghost-color, #333);
875
+ border: var(--compa11y-button-ghost-border, 1px solid transparent);
876
+ }
877
+
878
+ button.variant-ghost:hover:not(:disabled):not([aria-disabled="true"]) {
879
+ background: var(--compa11y-button-ghost-hover-bg, rgba(0, 0, 0, 0.05));
880
+ }
881
+
882
+ /* Disabled */
883
+ button:disabled,
884
+ button[aria-disabled="true"] {
885
+ opacity: var(--compa11y-button-disabled-opacity, 0.5);
886
+ cursor: not-allowed;
887
+ }
888
+
889
+ /* Loading spinner */
890
+ .button-spinner {
891
+ display: inline-block;
892
+ width: 1em;
893
+ height: 1em;
894
+ border: 2px solid currentColor;
895
+ border-right-color: transparent;
896
+ border-radius: 50%;
897
+ animation: compa11y-spin 0.6s linear infinite;
898
+ }
899
+ `, $e = `
900
+ ${b}
901
+
902
+ :host {
903
+ display: block;
904
+ width: var(--compa11y-listbox-width, 250px);
905
+ }
906
+
907
+ .listbox-wrapper {
908
+ max-height: var(--compa11y-listbox-max-height, 300px);
909
+ overflow-y: auto;
910
+ border: var(--compa11y-listbox-border, 1px solid #e0e0e0);
911
+ border-radius: var(--compa11y-listbox-radius, 4px);
912
+ background: var(--compa11y-listbox-bg, white);
913
+ padding: var(--compa11y-listbox-padding, 0.25rem 0);
914
+ }
915
+
916
+ :host([disabled]) .listbox-wrapper {
917
+ opacity: var(--compa11y-listbox-disabled-opacity, 0.5);
918
+ cursor: not-allowed;
919
+ }
920
+
921
+ :host(:focus-visible) .listbox-wrapper {
922
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
923
+ outline-offset: 2px;
924
+ }
925
+
926
+ :host([orientation="horizontal"]) .listbox-wrapper {
927
+ display: flex;
928
+ flex-wrap: wrap;
929
+ max-height: none;
930
+ overflow-y: visible;
931
+ }
932
+ `, Le = `
933
+ ${b}
934
+
935
+ :host {
936
+ display: block;
937
+ }
938
+
939
+ .option-wrapper {
940
+ display: flex;
941
+ align-items: center;
942
+ justify-content: space-between;
943
+ padding: var(--compa11y-listbox-option-padding, 0.5rem 0.75rem);
944
+ cursor: pointer;
945
+ transition: background 0.1s ease;
946
+ user-select: none;
947
+ }
948
+
949
+ :host([data-focused]) .option-wrapper {
950
+ background: var(--compa11y-listbox-option-hover-bg, #f5f5f5);
951
+ }
952
+
953
+ :host([aria-selected="true"]) .option-wrapper {
954
+ background: var(--compa11y-listbox-option-selected-bg, #e6f0ff);
955
+ font-weight: 500;
956
+ }
957
+
958
+ :host([aria-selected="true"][data-focused]) .option-wrapper {
959
+ background: var(--compa11y-listbox-option-selected-hover-bg, #cce0ff);
960
+ }
961
+
962
+ :host([aria-disabled="true"]) .option-wrapper {
963
+ opacity: 0.5;
964
+ cursor: not-allowed;
965
+ }
966
+
967
+ .option-content {
968
+ flex: 1;
969
+ }
970
+
971
+ .check-mark {
972
+ font-size: 0.875rem;
973
+ color: var(--compa11y-listbox-check-color, #0066cc);
974
+ margin-left: 0.5rem;
975
+ visibility: hidden;
976
+ }
977
+
978
+ :host([aria-selected="true"]) .check-mark {
979
+ visibility: visible;
980
+ }
981
+ `, Se = `
982
+ ${b}
983
+
984
+ :host {
985
+ display: block;
986
+ }
987
+
988
+ .optgroup-label {
989
+ padding: var(--compa11y-listbox-group-label-padding, 0.5rem 0.75rem 0.25rem);
990
+ font-size: var(--compa11y-listbox-group-label-size, 0.75rem);
991
+ font-weight: var(--compa11y-listbox-group-label-weight, 600);
992
+ color: var(--compa11y-listbox-group-label-color, #666);
993
+ text-transform: uppercase;
994
+ letter-spacing: 0.05em;
995
+ }
996
+
997
+ :host([disabled]) {
998
+ opacity: 0.5;
999
+ }
1000
+ `, Ie = `
1001
+ ${b}
1002
+
1003
+ :host {
1004
+ display: inline-block;
1005
+ }
1006
+
1007
+ .checkbox-wrapper {
1008
+ display: inline-flex;
1009
+ align-items: flex-start;
1010
+ gap: var(--compa11y-checkbox-gap, 0.5rem);
1011
+ cursor: pointer;
1012
+ user-select: none;
1013
+ }
1014
+
1015
+ :host([disabled]) .checkbox-wrapper {
1016
+ cursor: not-allowed;
1017
+ opacity: 0.5;
1018
+ }
1019
+
1020
+ .checkbox-control {
1021
+ position: relative;
1022
+ display: inline-flex;
1023
+ align-items: center;
1024
+ justify-content: center;
1025
+ flex-shrink: 0;
1026
+ }
1027
+
1028
+ .checkbox-input {
1029
+ position: absolute;
1030
+ opacity: 0;
1031
+ width: 100%;
1032
+ height: 100%;
1033
+ margin: 0;
1034
+ cursor: inherit;
1035
+ z-index: 1;
1036
+ }
1037
+
1038
+ .checkbox-indicator {
1039
+ width: var(--compa11y-checkbox-size, 1.25rem);
1040
+ height: var(--compa11y-checkbox-size, 1.25rem);
1041
+ min-width: 24px;
1042
+ min-height: 24px;
1043
+ border: var(--compa11y-checkbox-border, 2px solid #666);
1044
+ border-radius: var(--compa11y-checkbox-radius, 3px);
1045
+ background: var(--compa11y-checkbox-bg, white);
1046
+ display: flex;
1047
+ align-items: center;
1048
+ justify-content: center;
1049
+ flex-shrink: 0;
1050
+ transition: all 0.15s ease;
1051
+ pointer-events: none;
1052
+ }
1053
+
1054
+ :host([checked]) .checkbox-indicator {
1055
+ background: var(--compa11y-checkbox-checked-bg, #0066cc);
1056
+ border-color: var(--compa11y-checkbox-checked-border, #0066cc);
1057
+ }
1058
+
1059
+ :host([indeterminate]) .checkbox-indicator {
1060
+ background: var(--compa11y-checkbox-checked-bg, #0066cc);
1061
+ border-color: var(--compa11y-checkbox-checked-border, #0066cc);
1062
+ }
1063
+
1064
+ /* Size variants */
1065
+ .checkbox-wrapper.size-sm .checkbox-indicator {
1066
+ width: var(--compa11y-checkbox-size-sm, 1rem);
1067
+ height: var(--compa11y-checkbox-size-sm, 1rem);
1068
+ min-width: 24px;
1069
+ min-height: 24px;
1070
+ }
1071
+
1072
+ .checkbox-wrapper.size-lg .checkbox-indicator {
1073
+ width: var(--compa11y-checkbox-size-lg, 1.5rem);
1074
+ height: var(--compa11y-checkbox-size-lg, 1.5rem);
1075
+ }
1076
+
1077
+ /* Check mark SVG */
1078
+ .checkbox-check {
1079
+ opacity: 0;
1080
+ transform: scale(0);
1081
+ transition: all 0.15s ease;
1082
+ color: var(--compa11y-checkbox-check-color, white);
1083
+ }
1084
+
1085
+ :host([checked]) .checkbox-check {
1086
+ opacity: 1;
1087
+ transform: scale(1);
1088
+ }
1089
+
1090
+ :host([indeterminate]) .checkbox-check {
1091
+ opacity: 0;
1092
+ transform: scale(0);
1093
+ }
1094
+
1095
+ /* Indeterminate dash */
1096
+ .checkbox-dash {
1097
+ opacity: 0;
1098
+ transition: all 0.15s ease;
1099
+ color: var(--compa11y-checkbox-check-color, white);
1100
+ }
1101
+
1102
+ :host([indeterminate]) .checkbox-dash {
1103
+ opacity: 1;
1104
+ }
1105
+
1106
+ /* Focus visible on indicator when input is focused */
1107
+ .checkbox-input:focus-visible + .checkbox-indicator {
1108
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
1109
+ outline-offset: 2px;
1110
+ }
1111
+
1112
+ /* Hover */
1113
+ .checkbox-wrapper:hover:not([disabled]) .checkbox-indicator {
1114
+ border-color: var(--compa11y-checkbox-hover-border, #0066cc);
1115
+ }
1116
+
1117
+ /* Label and text */
1118
+ .checkbox-content {
1119
+ display: flex;
1120
+ flex-direction: column;
1121
+ gap: 0.125rem;
1122
+ padding-top: 0.125rem;
1123
+ }
1124
+
1125
+ .checkbox-label {
1126
+ color: var(--compa11y-checkbox-label-color, inherit);
1127
+ font-size: var(--compa11y-checkbox-label-size, 1rem);
1128
+ cursor: inherit;
1129
+ }
1130
+
1131
+ .checkbox-hint {
1132
+ color: var(--compa11y-checkbox-hint-color, #666);
1133
+ font-size: var(--compa11y-checkbox-hint-size, 0.8125rem);
1134
+ }
1135
+
1136
+ .checkbox-error {
1137
+ color: var(--compa11y-checkbox-error-color, #ef4444);
1138
+ font-size: var(--compa11y-checkbox-error-size, 0.8125rem);
1139
+ }
1140
+
1141
+ .checkbox-required {
1142
+ color: var(--compa11y-checkbox-required-color, #ef4444);
1143
+ margin-left: 0.125rem;
1144
+ }
1145
+
1146
+ /* Forced colors / high contrast mode */
1147
+ @media (forced-colors: active) {
1148
+ .checkbox-indicator {
1149
+ border: 2px solid ButtonText;
1150
+ }
1151
+
1152
+ :host([checked]) .checkbox-indicator,
1153
+ :host([indeterminate]) .checkbox-indicator {
1154
+ background: Highlight;
1155
+ border-color: Highlight;
1156
+ }
1157
+
1158
+ .checkbox-check,
1159
+ .checkbox-dash {
1160
+ color: HighlightText;
1161
+ }
1162
+ }
1163
+ `, Ce = `
1164
+ ${b}
1165
+
1166
+ :host {
1167
+ display: block;
1168
+ }
1169
+
1170
+ fieldset {
1171
+ border: none;
1172
+ margin: 0;
1173
+ padding: 0;
1174
+ min-width: 0;
1175
+ }
1176
+
1177
+ legend {
1178
+ padding: 0;
1179
+ margin-bottom: var(--compa11y-checkbox-group-legend-gap, 0.5rem);
1180
+ font-weight: var(--compa11y-checkbox-group-legend-weight, 600);
1181
+ color: var(--compa11y-checkbox-group-legend-color, inherit);
1182
+ font-size: var(--compa11y-checkbox-group-legend-size, 1rem);
1183
+ }
1184
+
1185
+ .checkbox-group-items {
1186
+ display: flex;
1187
+ flex-direction: column;
1188
+ gap: var(--compa11y-checkbox-group-gap, 0.75rem);
1189
+ }
1190
+
1191
+ :host([orientation="horizontal"]) .checkbox-group-items {
1192
+ flex-direction: row;
1193
+ flex-wrap: wrap;
1194
+ }
1195
+
1196
+ .checkbox-group-error {
1197
+ color: var(--compa11y-checkbox-group-error-color, #ef4444);
1198
+ font-size: var(--compa11y-checkbox-group-error-size, 0.8125rem);
1199
+ margin-top: 0.25rem;
1200
+ }
1201
+
1202
+ :host([disabled]) {
1203
+ opacity: 0.5;
1204
+ }
1205
+ `, ze = `
1206
+ ${b}
1207
+
1208
+ :host {
1209
+ display: block;
1210
+ }
1211
+
1212
+ fieldset {
1213
+ border: none;
1214
+ margin: 0;
1215
+ padding: 0;
1216
+ min-width: 0;
1217
+ }
1218
+
1219
+ legend {
1220
+ padding: 0;
1221
+ margin-bottom: var(--compa11y-radio-group-legend-gap, 0.5rem);
1222
+ font-weight: var(--compa11y-radio-group-legend-weight, 600);
1223
+ color: var(--compa11y-radio-group-legend-color, inherit);
1224
+ font-size: var(--compa11y-radio-group-legend-size, 1rem);
1225
+ }
1226
+
1227
+ .radio-group-items {
1228
+ display: flex;
1229
+ flex-direction: column;
1230
+ gap: var(--compa11y-radio-group-gap, 0.75rem);
1231
+ }
1232
+
1233
+ :host([orientation="horizontal"]) .radio-group-items {
1234
+ flex-direction: row;
1235
+ flex-wrap: wrap;
1236
+ }
1237
+
1238
+ .radio-group-hint {
1239
+ color: var(--compa11y-radio-group-hint-color, #666);
1240
+ font-size: var(--compa11y-radio-group-hint-size, 0.8125rem);
1241
+ margin-top: 0.25rem;
1242
+ }
1243
+
1244
+ .radio-group-error {
1245
+ color: var(--compa11y-radio-group-error-color, #ef4444);
1246
+ font-size: var(--compa11y-radio-group-error-size, 0.8125rem);
1247
+ margin-top: 0.25rem;
1248
+ }
1249
+
1250
+ .radio-group-required {
1251
+ color: var(--compa11y-radio-group-required-color, #ef4444);
1252
+ margin-left: 0.125rem;
1253
+ }
1254
+
1255
+ :host([disabled]) {
1256
+ opacity: 0.5;
1257
+ }
1258
+ `, qe = `
1259
+ ${b}
1260
+
1261
+ :host {
1262
+ display: inline-block;
1263
+ }
1264
+
1265
+ .radio-wrapper {
1266
+ display: inline-flex;
1267
+ align-items: flex-start;
1268
+ gap: var(--compa11y-radio-gap, 0.5rem);
1269
+ cursor: pointer;
1270
+ user-select: none;
1271
+ }
1272
+
1273
+ :host([disabled]) .radio-wrapper {
1274
+ cursor: not-allowed;
1275
+ opacity: 0.5;
1276
+ }
1277
+
1278
+ .radio-control {
1279
+ position: relative;
1280
+ display: inline-flex;
1281
+ align-items: center;
1282
+ justify-content: center;
1283
+ flex-shrink: 0;
1284
+ }
1285
+
1286
+ .radio-input {
1287
+ position: absolute;
1288
+ opacity: 0;
1289
+ width: 100%;
1290
+ height: 100%;
1291
+ margin: 0;
1292
+ cursor: inherit;
1293
+ z-index: 1;
1294
+ }
1295
+
1296
+ .radio-circle {
1297
+ width: var(--compa11y-radio-size, 1.25rem);
1298
+ height: var(--compa11y-radio-size, 1.25rem);
1299
+ min-width: 24px;
1300
+ min-height: 24px;
1301
+ border: var(--compa11y-radio-border, 2px solid #666);
1302
+ border-radius: 50%;
1303
+ background: var(--compa11y-radio-bg, white);
1304
+ display: flex;
1305
+ align-items: center;
1306
+ justify-content: center;
1307
+ flex-shrink: 0;
1308
+ transition: all 0.15s ease;
1309
+ pointer-events: none;
1310
+ }
1311
+
1312
+ :host([checked]) .radio-circle {
1313
+ background: var(--compa11y-radio-checked-bg, #0066cc);
1314
+ border-color: var(--compa11y-radio-checked-border, #0066cc);
1315
+ }
1316
+
1317
+ /* Focus visible on circle when input is focused */
1318
+ .radio-input:focus-visible + .radio-circle {
1319
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
1320
+ outline-offset: 2px;
1321
+ }
1322
+
1323
+ /* Hover */
1324
+ .radio-wrapper:hover:not([disabled]) .radio-circle {
1325
+ border-color: var(--compa11y-radio-hover-border, #0066cc);
1326
+ }
1327
+
1328
+ /* Inner dot */
1329
+ .radio-dot {
1330
+ width: var(--compa11y-radio-dot-size, 0.5rem);
1331
+ height: var(--compa11y-radio-dot-size, 0.5rem);
1332
+ border-radius: 50%;
1333
+ background: var(--compa11y-radio-dot-color, white);
1334
+ opacity: 0;
1335
+ transform: scale(0);
1336
+ transition: all 0.15s ease;
1337
+ }
1338
+
1339
+ :host([checked]) .radio-dot {
1340
+ opacity: 1;
1341
+ transform: scale(1);
1342
+ }
1343
+
1344
+ /* Label and text */
1345
+ .radio-content {
1346
+ display: flex;
1347
+ flex-direction: column;
1348
+ gap: 0.125rem;
1349
+ padding-top: 0.125rem;
1350
+ }
1351
+
1352
+ .radio-label {
1353
+ color: var(--compa11y-radio-label-color, inherit);
1354
+ font-size: var(--compa11y-radio-label-size, 1rem);
1355
+ cursor: inherit;
1356
+ }
1357
+
1358
+ .radio-hint {
1359
+ color: var(--compa11y-radio-hint-color, #666);
1360
+ font-size: var(--compa11y-radio-hint-size, 0.8125rem);
1361
+ }
1362
+
1363
+ /* Forced colors / high contrast mode */
1364
+ @media (forced-colors: active) {
1365
+ .radio-circle {
1366
+ border: 2px solid ButtonText;
1367
+ }
1368
+
1369
+ :host([checked]) .radio-circle {
1370
+ background: Highlight;
1371
+ border-color: Highlight;
1372
+ }
1373
+
1374
+ .radio-dot {
1375
+ background: HighlightText;
1376
+ }
1377
+ }
1378
+ `, B = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
1379
+ class M extends c {
1380
+ constructor() {
1381
+ super(...arguments), this._open = !1, this._previouslyFocused = null, this._triggerElement = null, this.handleTriggerClick = () => {
1382
+ this.open = !0;
1383
+ }, this.handleClose = () => {
1384
+ this.open = !1;
1385
+ }, this.handleKeyDown = (e) => {
1386
+ var t;
1387
+ if (this._open) {
1388
+ if (e.key === "Escape") {
1389
+ this.getAttribute("close-on-escape") !== "false" && (e.preventDefault(), this.handleClose());
1390
+ return;
1391
+ }
1392
+ if (e.key === "Tab") {
1393
+ e.preventDefault();
1394
+ const i = this.getFocusableElements();
1395
+ if (i.length === 0) return;
1396
+ const s = ((t = this.shadowRoot) == null ? void 0 : t.activeElement) || document.activeElement;
1397
+ let a = i.findIndex(
1398
+ (o) => o === s
1399
+ );
1400
+ a === -1 && (a = e.shiftKey ? 0 : i.length - 1);
1401
+ let r;
1402
+ e.shiftKey ? r = a === 0 ? i.length - 1 : a - 1 : r = a === i.length - 1 ? 0 : a + 1;
1403
+ const l = i[r];
1404
+ l && l.focus();
1405
+ }
1406
+ }
1407
+ };
1408
+ }
1409
+ static get observedAttributes() {
1410
+ return ["open", "trigger", "close-on-outside-click", "close-on-escape"];
1411
+ }
1412
+ get open() {
1413
+ return this._open;
1414
+ }
1415
+ set open(e) {
1416
+ const t = this._open;
1417
+ this._open = e, e !== t && (e ? this.showDialog() : this.hideDialog()), this.toggleAttribute("open", e);
1418
+ }
1419
+ setupAccessibility() {
1420
+ }
1421
+ render() {
1422
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-title`, i = `${this._id}-desc`;
1423
+ e.innerHTML = `
1424
+ <style>${ve}</style>
1425
+ <div class="overlay" part="overlay"></div>
1426
+ <div
1427
+ class="dialog"
1428
+ role="dialog"
1429
+ aria-modal="true"
1430
+ aria-labelledby="${t}"
1431
+ aria-describedby="${i}"
1432
+ part="dialog"
1433
+ >
1434
+ <div id="${t}" part="title">
1435
+ <slot name="title"></slot>
1436
+ </div>
1437
+ <div id="${i}" part="description">
1438
+ <slot name="description"></slot>
1439
+ </div>
1440
+ <div part="content">
1441
+ <slot></slot>
1442
+ </div>
1443
+ <div part="actions">
1444
+ <slot name="actions"></slot>
1445
+ </div>
1446
+ </div>
1447
+ `, this._open || (this.style.display = "none");
1448
+ }
1449
+ setupEventListeners() {
1450
+ var i;
1451
+ const e = this.getAttribute("trigger");
1452
+ if (e) {
1453
+ const s = () => {
1454
+ this._triggerElement = document.querySelector(e), this._triggerElement && (this._triggerElement.addEventListener(
1455
+ "click",
1456
+ this.handleTriggerClick
1457
+ ), this._triggerElement.hasAttribute("tabindex") || this._triggerElement.setAttribute("tabindex", "0"));
1458
+ };
1459
+ s(), this._triggerElement || requestAnimationFrame(() => {
1460
+ s(), this._triggerElement || setTimeout(s, 0);
1461
+ });
1462
+ }
1463
+ const t = (i = this.shadowRoot) == null ? void 0 : i.querySelector(".overlay");
1464
+ this.getAttribute("close-on-outside-click") !== "false" && (t == null || t.addEventListener("click", this.handleClose)), this.addEventListener("keydown", this.handleKeyDown);
1465
+ }
1466
+ cleanupEventListeners() {
1467
+ var e;
1468
+ (e = this._triggerElement) == null || e.removeEventListener("click", this.handleTriggerClick), this.removeEventListener("keydown", this.handleKeyDown);
1469
+ }
1470
+ onAttributeChange(e, t, i) {
1471
+ e === "open" && (this.open = i !== null);
1472
+ }
1473
+ /**
1474
+ * Get all focusable elements in the dialog (light DOM first, then shadow DOM)
1475
+ * Per WAI-ARIA best practices: focus should go to dialog content first,
1476
+ * close button should be last in tab order
1477
+ */
1478
+ getFocusableElements() {
1479
+ const e = [];
1480
+ return this.querySelectorAll(B).forEach((i) => e.push(i)), this.shadowRoot && this.shadowRoot.querySelectorAll(B).forEach((s) => {
1481
+ s.classList.contains("overlay") || e.push(s);
1482
+ }), e;
1483
+ }
1484
+ showDialog() {
1485
+ this._previouslyFocused = document.activeElement, this.style.display = "flex", requestAnimationFrame(() => {
1486
+ const t = this.getFocusableElements()[0];
1487
+ t && t.focus();
1488
+ }), document.body.style.overflow = "hidden", v("Dialog opened", { politeness: "polite" }), this.emit("a11y-dialog-open");
1489
+ }
1490
+ hideDialog() {
1491
+ var e;
1492
+ this.style.display = "none", document.body.style.overflow = "", (e = this._previouslyFocused) == null || e.focus(), this._previouslyFocused = null, v("Dialog closed", { politeness: "polite" }), this.emit("a11y-dialog-close");
1493
+ }
1494
+ /**
1495
+ * Programmatic open
1496
+ */
1497
+ show() {
1498
+ this.open = !0;
1499
+ }
1500
+ /**
1501
+ * Programmatic close
1502
+ */
1503
+ close() {
1504
+ this.open = !1;
1505
+ }
1506
+ }
1507
+ u("a11y-dialog", M);
1508
+ class K extends c {
1509
+ constructor() {
1510
+ super(...arguments), this._open = !1, this._highlightedIndex = -1, this._menuItems = [], this.updateMenuItems = () => {
1511
+ this._menuItems = Array.from(
1512
+ this.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')
1513
+ ), this._menuItems.forEach((e, t) => {
1514
+ e.id = e.id || `${this._id}-item-${t}`, e.setAttribute("tabindex", "-1");
1515
+ });
1516
+ }, this._lastClickTime = 0, this.handleTriggerClick = () => {
1517
+ const e = Date.now();
1518
+ e - this._lastClickTime < 50 || (this._lastClickTime = e, this.toggle());
1519
+ }, this.handleTriggerKeyDown = (e) => {
1520
+ switch (e.key) {
1521
+ case "Enter":
1522
+ case " ":
1523
+ e.preventDefault(), this.toggle(), this._open && this.highlightItem(0);
1524
+ break;
1525
+ case "ArrowDown":
1526
+ e.preventDefault(), this._open || this.show(), this.highlightItem(0);
1527
+ break;
1528
+ case "ArrowUp":
1529
+ e.preventDefault(), this._open || this.show(), this.highlightItem(this._menuItems.length - 1);
1530
+ break;
1531
+ }
1532
+ }, this.handleMenuKeyDown = (e) => {
1533
+ if (!this._open) return;
1534
+ const t = e.target;
1535
+ if (!(!t.hasAttribute("role") || t.getAttribute("role") !== "menuitem"))
1536
+ switch (e.key) {
1537
+ case "ArrowDown":
1538
+ e.preventDefault(), this.highlightItem(
1539
+ (this._highlightedIndex + 1) % this._menuItems.length
1540
+ );
1541
+ break;
1542
+ case "ArrowUp":
1543
+ e.preventDefault(), this.highlightItem(
1544
+ (this._highlightedIndex - 1 + this._menuItems.length) % this._menuItems.length
1545
+ );
1546
+ break;
1547
+ case "Home":
1548
+ e.preventDefault(), this.highlightItem(0);
1549
+ break;
1550
+ case "End":
1551
+ e.preventDefault(), this.highlightItem(this._menuItems.length - 1);
1552
+ break;
1553
+ case "Enter":
1554
+ case " ":
1555
+ e.preventDefault(), this.selectItem(this._highlightedIndex);
1556
+ break;
1557
+ case "Escape":
1558
+ e.preventDefault(), this.close();
1559
+ break;
1560
+ case "Tab":
1561
+ this.close();
1562
+ break;
1563
+ }
1564
+ }, this.handleItemClick = (e) => {
1565
+ const t = e.target;
1566
+ if (t.getAttribute("role") === "menuitem" && t.getAttribute("aria-disabled") !== "true") {
1567
+ const i = this._menuItems.indexOf(t);
1568
+ this.selectItem(i);
1569
+ }
1570
+ }, this.handleMouseOver = (e) => {
1571
+ const t = e.target;
1572
+ if (t.getAttribute("role") === "menuitem") {
1573
+ const i = this._menuItems.indexOf(t);
1574
+ i !== -1 && this.highlightItem(i, !1);
1575
+ }
1576
+ }, this.handleOutsideClick = (e) => {
1577
+ if (!this._open) return;
1578
+ e.composedPath().includes(this) || this.close();
1579
+ };
1580
+ }
1581
+ static get observedAttributes() {
1582
+ return ["open"];
1583
+ }
1584
+ get open() {
1585
+ return this._open;
1586
+ }
1587
+ set open(e) {
1588
+ const t = this._open;
1589
+ this._open = e, e !== t && this.updateMenuVisibility(), this.toggleAttribute("open", e);
1590
+ }
1591
+ setupAccessibility() {
1592
+ const e = this.querySelector('[slot="trigger"]');
1593
+ e && (e.setAttribute("aria-haspopup", "menu"), e.setAttribute("aria-expanded", String(this._open)), e.id = e.id || `${this._id}-trigger`, e.hasAttribute("tabindex") || e.setAttribute("tabindex", "0"));
1594
+ }
1595
+ render() {
1596
+ const e = this.attachShadow({ mode: "open" });
1597
+ e.innerHTML = `
1598
+ <style>${fe}</style>
1599
+ <slot name="trigger"></slot>
1600
+ <div
1601
+ class="menu-content"
1602
+ role="menu"
1603
+ aria-labelledby="${this._id}-trigger"
1604
+ tabindex="-1"
1605
+ hidden
1606
+ part="menu"
1607
+ >
1608
+ <slot></slot>
1609
+ </div>
1610
+ `;
1611
+ }
1612
+ setupEventListeners() {
1613
+ var s, a;
1614
+ const e = this.querySelector('[slot="trigger"]');
1615
+ e == null || e.addEventListener("click", this.handleTriggerClick), e == null || e.addEventListener(
1616
+ "keydown",
1617
+ this.handleTriggerKeyDown
1618
+ );
1619
+ const t = (s = this.shadowRoot) == null ? void 0 : s.querySelector('slot[name="trigger"]');
1620
+ t == null || t.addEventListener("click", this.handleTriggerClick), this.addEventListener("click", this.handleItemClick), this.addEventListener("keydown", this.handleMenuKeyDown), this.addEventListener("mouseover", this.handleMouseOver), document.addEventListener("mousedown", this.handleOutsideClick);
1621
+ const i = (a = this.shadowRoot) == null ? void 0 : a.querySelector("slot:not([name])");
1622
+ i == null || i.addEventListener("slotchange", this.updateMenuItems), this.updateMenuItems();
1623
+ }
1624
+ cleanupEventListeners() {
1625
+ document.removeEventListener("mousedown", this.handleOutsideClick);
1626
+ }
1627
+ onAttributeChange(e, t, i) {
1628
+ e === "open" && (this.open = i !== null);
1629
+ }
1630
+ highlightItem(e, t = !0) {
1631
+ var s;
1632
+ if (this._highlightedIndex >= 0) {
1633
+ const a = this._menuItems[this._highlightedIndex];
1634
+ a == null || a.removeAttribute("data-highlighted");
1635
+ }
1636
+ this._highlightedIndex = e;
1637
+ const i = this._menuItems[e];
1638
+ if (i) {
1639
+ i.setAttribute("data-highlighted", "true"), t && i.focus();
1640
+ const a = (s = this.shadowRoot) == null ? void 0 : s.querySelector('[role="menu"]');
1641
+ a == null || a.setAttribute("aria-activedescendant", i.id);
1642
+ }
1643
+ }
1644
+ selectItem(e) {
1645
+ const t = this._menuItems[e];
1646
+ t && (this.emit("a11y-menu-select", { item: t, index: e }), t.click()), this.close();
1647
+ }
1648
+ updateMenuVisibility() {
1649
+ var i;
1650
+ const e = (i = this.shadowRoot) == null ? void 0 : i.querySelector(".menu-content"), t = this.querySelector('[slot="trigger"]');
1651
+ this._open ? (e == null || e.removeAttribute("hidden"), t == null || t.setAttribute("aria-expanded", "true"), this.updateMenuItems(), this.emit("a11y-menu-open")) : (e == null || e.setAttribute("hidden", ""), t == null || t.setAttribute("aria-expanded", "false"), this._highlightedIndex = -1, this._menuItems.forEach((s) => {
1652
+ s.removeAttribute("data-highlighted");
1653
+ }), t == null || t.focus(), this.emit("a11y-menu-close"));
1654
+ }
1655
+ /**
1656
+ * Show the menu
1657
+ */
1658
+ show() {
1659
+ this.open = !0;
1660
+ }
1661
+ /**
1662
+ * Hide the menu
1663
+ */
1664
+ close() {
1665
+ this.open = !1;
1666
+ }
1667
+ /**
1668
+ * Toggle the menu
1669
+ */
1670
+ toggle() {
1671
+ this.open = !this._open;
1672
+ }
1673
+ }
1674
+ u("a11y-menu", K);
1675
+ class F extends c {
1676
+ constructor() {
1677
+ super(...arguments), this._tabs = [], this._panels = [], this._selectedIndex = 0, this.updateTabsAndPanels = () => {
1678
+ this._tabs = Array.from(
1679
+ this.querySelectorAll('[role="tab"]')
1680
+ ), this._panels = Array.from(
1681
+ this.querySelectorAll('[role="tabpanel"]')
1682
+ ), this._tabs.forEach((e, t) => {
1683
+ const i = this._panels[t], s = e.id || `${this._id}-tab-${t}`, a = (i == null ? void 0 : i.id) || `${this._id}-panel-${t}`;
1684
+ e.id = s, e.setAttribute("aria-controls", a), e.setAttribute("tabindex", t === this._selectedIndex ? "0" : "-1"), e.setAttribute("aria-selected", String(t === this._selectedIndex)), e.hasAttribute("slot") || e.setAttribute("slot", "tab"), i && (i.id = a, i.setAttribute("aria-labelledby", s), i.setAttribute("tabindex", "0"), i.hidden = t !== this._selectedIndex, i.hasAttribute("slot") || i.setAttribute("slot", "panel"));
1685
+ }), this.updateSelection();
1686
+ }, this.handleClick = (e) => {
1687
+ const t = e.target;
1688
+ if (t.getAttribute("role") === "tab") {
1689
+ const i = this._tabs.indexOf(t);
1690
+ i !== -1 && t.getAttribute("aria-disabled") !== "true" && this.selectTab(i);
1691
+ }
1692
+ }, this.handleKeyDown = (e) => {
1693
+ var l;
1694
+ if (e.target.getAttribute("role") !== "tab") return;
1695
+ const i = this.orientation === "horizontal", s = i ? "ArrowRight" : "ArrowDown", a = i ? "ArrowLeft" : "ArrowUp";
1696
+ let r = this._selectedIndex;
1697
+ switch (e.key) {
1698
+ case s:
1699
+ e.preventDefault(), r = (this._selectedIndex + 1) % this._tabs.length;
1700
+ break;
1701
+ case a:
1702
+ e.preventDefault(), r = (this._selectedIndex - 1 + this._tabs.length) % this._tabs.length;
1703
+ break;
1704
+ case "Home":
1705
+ e.preventDefault(), r = 0;
1706
+ break;
1707
+ case "End":
1708
+ e.preventDefault(), r = this._tabs.length - 1;
1709
+ break;
1710
+ default:
1711
+ return;
1712
+ }
1713
+ (l = this._tabs[r]) == null || l.focus(), this.activationMode === "automatic" && this.selectTab(r);
1714
+ };
1715
+ }
1716
+ static get observedAttributes() {
1717
+ return ["orientation", "activation-mode", "selected-index"];
1718
+ }
1719
+ get selectedIndex() {
1720
+ return this._selectedIndex;
1721
+ }
1722
+ set selectedIndex(e) {
1723
+ e >= 0 && e < this._tabs.length && (this._selectedIndex = e, this.updateSelection());
1724
+ }
1725
+ get orientation() {
1726
+ return this.getAttribute("orientation") || "horizontal";
1727
+ }
1728
+ get activationMode() {
1729
+ return this.getAttribute("activation-mode") || "automatic";
1730
+ }
1731
+ setupAccessibility() {
1732
+ this.updateTabsAndPanels();
1733
+ }
1734
+ render() {
1735
+ const e = this.attachShadow({ mode: "open" });
1736
+ e.innerHTML = `
1737
+ <style>${_e}</style>
1738
+ <div class="tablist" role="tablist" aria-orientation="${this.orientation}" part="tablist">
1739
+ <slot name="tab"></slot>
1740
+ </div>
1741
+ <div class="panels" part="panels">
1742
+ <slot name="panel"></slot>
1743
+ </div>
1744
+ <slot></slot>
1745
+ `;
1746
+ }
1747
+ setupEventListeners() {
1748
+ var s, a, r;
1749
+ this.addEventListener("click", this.handleClick), this.addEventListener("keydown", this.handleKeyDown);
1750
+ const e = (s = this.shadowRoot) == null ? void 0 : s.querySelector('slot[name="tab"]'), t = (a = this.shadowRoot) == null ? void 0 : a.querySelector('slot[name="panel"]'), i = (r = this.shadowRoot) == null ? void 0 : r.querySelector("slot:not([name])");
1751
+ e == null || e.addEventListener("slotchange", this.updateTabsAndPanels), t == null || t.addEventListener("slotchange", this.updateTabsAndPanels), i == null || i.addEventListener("slotchange", this.updateTabsAndPanels);
1752
+ }
1753
+ onAttributeChange(e, t, i) {
1754
+ var s;
1755
+ if (e === "orientation") {
1756
+ const a = (s = this.shadowRoot) == null ? void 0 : s.querySelector('[role="tablist"]');
1757
+ a == null || a.setAttribute("aria-orientation", i || "horizontal");
1758
+ }
1759
+ e === "selected-index" && i && (this.selectedIndex = parseInt(i, 10));
1760
+ }
1761
+ selectTab(e) {
1762
+ const t = this._selectedIndex;
1763
+ if (this._selectedIndex = e, this.updateSelection(), t !== e) {
1764
+ const i = this._tabs[e];
1765
+ v(`${(i == null ? void 0 : i.textContent) || "Tab"} selected`), this.emit("a11y-tabs-change", {
1766
+ index: e,
1767
+ tab: this._tabs[e],
1768
+ panel: this._panels[e]
1769
+ });
1770
+ }
1771
+ }
1772
+ updateSelection() {
1773
+ this._tabs.forEach((e, t) => {
1774
+ const i = t === this._selectedIndex;
1775
+ e.setAttribute("aria-selected", String(i)), e.setAttribute("tabindex", i ? "0" : "-1");
1776
+ }), this._panels.forEach((e, t) => {
1777
+ e.hidden = t !== this._selectedIndex;
1778
+ });
1779
+ }
1780
+ /**
1781
+ * Select a tab by index
1782
+ */
1783
+ select(e) {
1784
+ this.selectTab(e);
1785
+ }
1786
+ /**
1787
+ * Select next tab
1788
+ */
1789
+ next() {
1790
+ this.selectTab((this._selectedIndex + 1) % this._tabs.length);
1791
+ }
1792
+ /**
1793
+ * Select previous tab
1794
+ */
1795
+ previous() {
1796
+ this.selectTab(
1797
+ (this._selectedIndex - 1 + this._tabs.length) % this._tabs.length
1798
+ );
1799
+ }
1800
+ }
1801
+ u("a11y-tabs", F);
1802
+ class N extends c {
1803
+ constructor() {
1804
+ super(...arguments), this._open = !1, this._highlightedIndex = -1, this._options = [], this._filteredOptions = [], this._inputValue = "", this._selectedValue = null, this._inputElement = null, this._listboxElement = null, this.updateOptions = () => {
1805
+ const e = Array.from(this.querySelectorAll("option"));
1806
+ this._options = e.map((t) => ({
1807
+ value: t.getAttribute("value") || t.textContent || "",
1808
+ label: t.textContent || "",
1809
+ disabled: t.hasAttribute("disabled"),
1810
+ element: t
1811
+ })), this._filteredOptions = [...this._options], this.renderOptions();
1812
+ }, this.handleInput = (e) => {
1813
+ const t = e.target;
1814
+ this._inputValue = t.value;
1815
+ const i = this._inputValue.toLowerCase();
1816
+ this._filteredOptions = i ? this._options.filter((a) => a.label.toLowerCase().includes(i)) : [...this._options], this.renderOptions(), this.open = !0, this._highlightedIndex = 0, this.updateHighlight(), this.updateClearButton();
1817
+ const s = this._filteredOptions.length;
1818
+ v(
1819
+ s === 0 ? "No results" : `${s} result${s === 1 ? "" : "s"} available`
1820
+ );
1821
+ }, this.handleFocus = () => {
1822
+ this.open = !0;
1823
+ }, this.handleBlur = () => {
1824
+ setTimeout(() => {
1825
+ var e;
1826
+ (e = this.shadowRoot) != null && e.activeElement || (this.open = !1);
1827
+ }, 150);
1828
+ }, this.handleKeyDown = (e) => {
1829
+ switch (e.key) {
1830
+ case "ArrowDown":
1831
+ e.preventDefault(), this._open ? this._highlightedIndex = Math.min(
1832
+ this._highlightedIndex + 1,
1833
+ this._filteredOptions.length - 1
1834
+ ) : (this.open = !0, this._highlightedIndex = 0), this.updateHighlight();
1835
+ break;
1836
+ case "ArrowUp":
1837
+ e.preventDefault(), this._open ? this._highlightedIndex = Math.max(this._highlightedIndex - 1, 0) : (this.open = !0, this._highlightedIndex = this._filteredOptions.length - 1), this.updateHighlight();
1838
+ break;
1839
+ case "Enter":
1840
+ if (e.preventDefault(), this._open && this._highlightedIndex >= 0) {
1841
+ const t = this._filteredOptions[this._highlightedIndex];
1842
+ t && !t.disabled && this.selectOption(t);
1843
+ }
1844
+ break;
1845
+ case "Escape":
1846
+ e.preventDefault(), this.open = !1, this._highlightedIndex = -1;
1847
+ break;
1848
+ case "Home":
1849
+ this._open && (e.preventDefault(), this._highlightedIndex = 0, this.updateHighlight());
1850
+ break;
1851
+ case "End":
1852
+ this._open && (e.preventDefault(), this._highlightedIndex = this._filteredOptions.length - 1, this.updateHighlight());
1853
+ break;
1854
+ case "Tab":
1855
+ this._open && (this.open = !1, this._highlightedIndex = -1);
1856
+ break;
1857
+ }
1858
+ }, this.handleOptionClick = (e) => {
1859
+ const t = e.currentTarget, i = parseInt(t.dataset.index || "0", 10), s = this._filteredOptions[i];
1860
+ s && !s.disabled && this.selectOption(s);
1861
+ }, this.handleOptionHover = (e) => {
1862
+ const t = e.currentTarget, i = parseInt(t.dataset.index || "0", 10), s = this._filteredOptions[i];
1863
+ s && !s.disabled && (this._highlightedIndex = i, this.updateHighlight());
1864
+ }, this.handleClear = () => {
1865
+ this._inputValue = "", this._selectedValue = null, this._inputElement && (this._inputElement.value = "", this._inputElement.focus()), this._filteredOptions = [...this._options], this.renderOptions(), this.updateClearButton(), this.emit("a11y-combobox-clear"), this.emit("a11y-combobox-change", { value: null, label: null });
1866
+ }, this.handleOutsideClick = (e) => {
1867
+ if (!this._open) return;
1868
+ e.composedPath().includes(this) || (this.open = !1);
1869
+ };
1870
+ }
1871
+ static get observedAttributes() {
1872
+ return ["open", "value", "placeholder", "disabled", "clearable"];
1873
+ }
1874
+ get open() {
1875
+ return this._open;
1876
+ }
1877
+ set open(e) {
1878
+ const t = this._open;
1879
+ this._open = e, e !== t && this.updateListboxVisibility(), this.toggleAttribute("open", e);
1880
+ }
1881
+ get value() {
1882
+ return this._selectedValue;
1883
+ }
1884
+ set value(e) {
1885
+ this._selectedValue = e;
1886
+ const t = this._options.find((i) => i.value === e);
1887
+ t && (this._inputValue = t.label, this._inputElement && (this._inputElement.value = t.label)), this.setAttribute("value", e || "");
1888
+ }
1889
+ setupAccessibility() {
1890
+ }
1891
+ render() {
1892
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-input`, i = `${this._id}-listbox`, s = this.getAttribute("placeholder") || "Search...", a = this.hasAttribute("clearable");
1893
+ e.innerHTML = `
1894
+ <style>${ye}</style>
1895
+ <div class="combobox-wrapper" part="wrapper">
1896
+ <div class="input-wrapper" part="input-wrapper">
1897
+ <input
1898
+ id="${t}"
1899
+ type="text"
1900
+ role="combobox"
1901
+ autocomplete="off"
1902
+ aria-expanded="false"
1903
+ aria-controls="${i}"
1904
+ aria-haspopup="listbox"
1905
+ aria-autocomplete="list"
1906
+ placeholder="${s}"
1907
+ part="input"
1908
+ />
1909
+ ${a ? `
1910
+ <button
1911
+ type="button"
1912
+ class="clear-button"
1913
+ aria-label="Clear selection"
1914
+ tabindex="-1"
1915
+ hidden
1916
+ part="clear-button"
1917
+ >×</button>
1918
+ ` : ""}
1919
+ <span class="chevron" aria-hidden="true" part="chevron">▼</span>
1920
+ </div>
1921
+ <ul
1922
+ id="${i}"
1923
+ role="listbox"
1924
+ aria-labelledby="${t}"
1925
+ class="listbox"
1926
+ tabindex="-1"
1927
+ hidden
1928
+ part="listbox"
1929
+ ></ul>
1930
+ </div>
1931
+ <div class="options-source" hidden>
1932
+ <slot></slot>
1933
+ </div>
1934
+ `, this._inputElement = e.querySelector("input"), this._listboxElement = e.querySelector(".listbox");
1935
+ }
1936
+ setupEventListeners() {
1937
+ var i, s, a, r, l, o;
1938
+ (i = this._inputElement) == null || i.addEventListener("input", this.handleInput), (s = this._inputElement) == null || s.addEventListener("focus", this.handleFocus), (a = this._inputElement) == null || a.addEventListener("blur", this.handleBlur), (r = this._inputElement) == null || r.addEventListener("keydown", this.handleKeyDown);
1939
+ const e = (l = this.shadowRoot) == null ? void 0 : l.querySelector(".clear-button");
1940
+ e == null || e.addEventListener("click", this.handleClear), document.addEventListener("mousedown", this.handleOutsideClick);
1941
+ const t = (o = this.shadowRoot) == null ? void 0 : o.querySelector("slot");
1942
+ t == null || t.addEventListener("slotchange", this.updateOptions), this.updateOptions();
1943
+ }
1944
+ cleanupEventListeners() {
1945
+ document.removeEventListener("mousedown", this.handleOutsideClick);
1946
+ }
1947
+ onAttributeChange(e, t, i) {
1948
+ e === "open" && (this.open = i !== null), e === "value" && (this.value = i), e === "disabled" && this._inputElement && (this._inputElement.disabled = i !== null), e === "placeholder" && this._inputElement && (this._inputElement.placeholder = i || "Search...");
1949
+ }
1950
+ renderOptions() {
1951
+ this._listboxElement && (this._listboxElement.innerHTML = this._filteredOptions.length === 0 ? '<li role="presentation" class="empty-message" part="empty">No results found</li>' : this._filteredOptions.map(
1952
+ (e, t) => `
1953
+ <li
1954
+ id="${this._id}-option-${t}"
1955
+ role="option"
1956
+ aria-selected="${this._selectedValue === e.value}"
1957
+ aria-disabled="${e.disabled}"
1958
+ data-value="${e.value}"
1959
+ data-index="${t}"
1960
+ part="option"
1961
+ ${e.disabled ? 'class="disabled"' : ""}
1962
+ >${e.label}</li>
1963
+ `
1964
+ ).join(""), this._listboxElement.querySelectorAll('[role="option"]').forEach((e) => {
1965
+ e.addEventListener("click", this.handleOptionClick), e.addEventListener("mouseenter", this.handleOptionHover);
1966
+ }));
1967
+ }
1968
+ selectOption(e) {
1969
+ this._selectedValue = e.value, this._inputValue = e.label, this._inputElement && (this._inputElement.value = e.label), this.open = !1, this._highlightedIndex = -1, this.renderOptions(), this.updateClearButton(), v(`${e.label} selected`), this.emit("a11y-combobox-select", {
1970
+ value: e.value,
1971
+ label: e.label
1972
+ }), this.emit("a11y-combobox-change", {
1973
+ value: e.value,
1974
+ label: e.label
1975
+ });
1976
+ }
1977
+ updateHighlight() {
1978
+ var e, t, i, s;
1979
+ if ((e = this._listboxElement) == null || e.querySelectorAll('[role="option"]').forEach((a, r) => {
1980
+ a.classList.toggle("highlighted", r === this._highlightedIndex);
1981
+ }), this._highlightedIndex >= 0) {
1982
+ const a = `${this._id}-option-${this._highlightedIndex}`;
1983
+ (t = this._inputElement) == null || t.setAttribute("aria-activedescendant", a);
1984
+ const r = (i = this._listboxElement) == null ? void 0 : i.querySelector(`#${a}`);
1985
+ r == null || r.scrollIntoView({ block: "nearest", behavior: "smooth" });
1986
+ } else
1987
+ (s = this._inputElement) == null || s.removeAttribute("aria-activedescendant");
1988
+ }
1989
+ updateListboxVisibility() {
1990
+ !this._listboxElement || !this._inputElement || (this._open ? (this._listboxElement.hidden = !1, this._inputElement.setAttribute("aria-expanded", "true"), this.updateListboxPosition(), this.emit("a11y-combobox-open")) : (this._listboxElement.hidden = !0, this._inputElement.setAttribute("aria-expanded", "false"), this._highlightedIndex = -1, this.updateHighlight(), this._listboxElement.style.top = "", this._listboxElement.style.bottom = "", this.removeAttribute("data-position"), this.emit("a11y-combobox-close")));
1991
+ }
1992
+ updateListboxPosition() {
1993
+ if (!this._listboxElement || !this._inputElement) return;
1994
+ const e = this._inputElement.getBoundingClientRect(), t = window.innerHeight, i = Math.min(
1995
+ this._listboxElement.scrollHeight,
1996
+ 200
1997
+ // max-height from CSS
1998
+ ), s = t - e.bottom, a = e.top;
1999
+ s < i + 8 && a > s ? (this._listboxElement.style.top = "auto", this._listboxElement.style.bottom = "100%", this._listboxElement.style.marginTop = "0", this._listboxElement.style.marginBottom = "4px", this.setAttribute("data-position", "top")) : (this._listboxElement.style.top = "100%", this._listboxElement.style.bottom = "auto", this._listboxElement.style.marginTop = "4px", this._listboxElement.style.marginBottom = "0", this.setAttribute("data-position", "bottom"));
2000
+ }
2001
+ updateClearButton() {
2002
+ var t;
2003
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector(
2004
+ ".clear-button"
2005
+ );
2006
+ e && (e.hidden = !this._inputValue);
2007
+ }
2008
+ /**
2009
+ * Programmatic open
2010
+ */
2011
+ show() {
2012
+ this.open = !0;
2013
+ }
2014
+ /**
2015
+ * Programmatic close
2016
+ */
2017
+ close() {
2018
+ this.open = !1;
2019
+ }
2020
+ /**
2021
+ * Clear the selection
2022
+ */
2023
+ clear() {
2024
+ this.handleClear();
2025
+ }
2026
+ }
2027
+ u("a11y-combobox", N);
2028
+ class P extends c {
2029
+ constructor() {
2030
+ super(...arguments), this._checked = !1, this._button = null, this._label = null, this.handleClick = () => {
2031
+ this.toggle();
2032
+ }, this.handleKeyDown = (e) => {
2033
+ this.disabled || (e.key === " " || e.key === "Enter") && (e.preventDefault(), this.toggle());
2034
+ }, this.handleLabelClick = () => {
2035
+ var e;
2036
+ this.disabled || (this.toggle(), (e = this._button) == null || e.focus());
2037
+ };
2038
+ }
2039
+ static get observedAttributes() {
2040
+ return ["checked", "disabled", "label", "size", "aria-label"];
2041
+ }
2042
+ /**
2043
+ * Get/set the checked state
2044
+ */
2045
+ get checked() {
2046
+ return this._checked;
2047
+ }
2048
+ set checked(e) {
2049
+ const t = this._checked;
2050
+ this._checked = e, this.toggleAttribute("checked", e), e !== t && (this.updateVisualState(), this.emit("change", { checked: e }));
2051
+ }
2052
+ /**
2053
+ * Get/set the disabled state
2054
+ */
2055
+ get disabled() {
2056
+ return this.hasAttribute("disabled");
2057
+ }
2058
+ set disabled(e) {
2059
+ this.toggleAttribute("disabled", e), this.updateDisabledState();
2060
+ }
2061
+ /**
2062
+ * Get/set the visible label
2063
+ */
2064
+ get label() {
2065
+ return this.getAttribute("label") || "";
2066
+ }
2067
+ set label(e) {
2068
+ e ? this.setAttribute("label", e) : this.removeAttribute("label");
2069
+ }
2070
+ /**
2071
+ * Get/set the size variant
2072
+ */
2073
+ get size() {
2074
+ const e = this.getAttribute("size");
2075
+ return e === "sm" || e === "lg" ? e : "md";
2076
+ }
2077
+ set size(e) {
2078
+ this.setAttribute("size", e);
2079
+ }
2080
+ setupAccessibility() {
2081
+ var e;
2082
+ this.getAttribute("role"), typeof process < "u" && ((e = process.env) == null ? void 0 : e.NODE_ENV) !== "production" && !this.label && !this.getAttribute("aria-label") && console.warn(
2083
+ `[compa11y/Switch] Switch has no accessible label. Add label="..." or aria-label="..." attribute.
2084
+ 💡 Suggestion: <a11y-switch label="Enable feature"></a11y-switch>`
2085
+ );
2086
+ }
2087
+ render() {
2088
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-label`, i = !!this.label, s = this.getAttribute("aria-label"), a = i ? "" : s ? `aria-label="${s}"` : "", r = i ? `aria-labelledby="${t}"` : "";
2089
+ e.innerHTML = `
2090
+ <style>${Ae}</style>
2091
+ <div class="switch-wrapper size-${this.size}" part="wrapper">
2092
+ <button
2093
+ type="button"
2094
+ role="switch"
2095
+ aria-checked="${this._checked}"
2096
+ ${a}
2097
+ ${r}
2098
+ ${this.disabled ? "disabled" : ""}
2099
+ class="switch-track ${this._checked ? "checked" : ""}"
2100
+ part="track"
2101
+ tabindex="${this.disabled ? "-1" : "0"}"
2102
+ >
2103
+ <span class="switch-thumb" part="thumb" aria-hidden="true"></span>
2104
+ </button>
2105
+ ${i ? `<label id="${t}" class="switch-label ${this.disabled ? "disabled" : ""}" part="label">${this.label}</label>` : ""}
2106
+ </div>
2107
+ `, this._button = e.querySelector("button"), this._label = e.querySelector("label");
2108
+ }
2109
+ setupEventListeners() {
2110
+ var e, t, i;
2111
+ (e = this._button) == null || e.addEventListener("click", this.handleClick), (t = this._button) == null || t.addEventListener("keydown", this.handleKeyDown), (i = this._label) == null || i.addEventListener("click", this.handleLabelClick);
2112
+ }
2113
+ cleanupEventListeners() {
2114
+ var e, t, i;
2115
+ (e = this._button) == null || e.removeEventListener("click", this.handleClick), (t = this._button) == null || t.removeEventListener("keydown", this.handleKeyDown), (i = this._label) == null || i.removeEventListener("click", this.handleLabelClick);
2116
+ }
2117
+ onAttributeChange(e, t, i) {
2118
+ switch (e) {
2119
+ case "checked":
2120
+ this._checked = i !== null, this.updateVisualState();
2121
+ break;
2122
+ case "disabled":
2123
+ this.updateDisabledState();
2124
+ break;
2125
+ case "label":
2126
+ case "aria-label":
2127
+ this.shadowRoot && (this.shadowRoot.innerHTML = "", this.render(), this.setupEventListeners());
2128
+ break;
2129
+ case "size":
2130
+ this.updateSizeClass();
2131
+ break;
2132
+ }
2133
+ }
2134
+ /**
2135
+ * Update the visual state (checked class and aria-checked)
2136
+ */
2137
+ updateVisualState() {
2138
+ this._button && (this._button.setAttribute("aria-checked", String(this._checked)), this._button.classList.toggle("checked", this._checked));
2139
+ }
2140
+ /**
2141
+ * Update the disabled state
2142
+ */
2143
+ updateDisabledState() {
2144
+ this._button && (this.disabled ? (this._button.setAttribute("disabled", ""), this._button.setAttribute("tabindex", "-1")) : (this._button.removeAttribute("disabled"), this._button.setAttribute("tabindex", "0"))), this._label && this._label.classList.toggle("disabled", this.disabled);
2145
+ }
2146
+ /**
2147
+ * Update the size class
2148
+ */
2149
+ updateSizeClass() {
2150
+ var t;
2151
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector(".switch-wrapper");
2152
+ e && (e.classList.remove("size-sm", "size-md", "size-lg"), e.classList.add(`size-${this.size}`));
2153
+ }
2154
+ /**
2155
+ * Public method to toggle the switch programmatically
2156
+ */
2157
+ toggle() {
2158
+ if (this.disabled) return;
2159
+ this.checked = !this.checked;
2160
+ const e = this.label || this.getAttribute("aria-label") || "Switch";
2161
+ p(`${e} ${this.checked ? "on" : "off"}`);
2162
+ }
2163
+ /**
2164
+ * Public method to open/close programmatically
2165
+ */
2166
+ setChecked(e) {
2167
+ this.checked = e;
2168
+ }
2169
+ }
2170
+ u("a11y-switch", P);
2171
+ class j extends c {
2172
+ constructor() {
2173
+ super(...arguments), this._open = !1, this._highlightedIndex = -1, this._options = [], this._selectedValue = null, this._triggerElement = null, this._listboxElement = null, this._typeAhead = null, this.updateOptions = () => {
2174
+ const e = Array.from(this.querySelectorAll("option"));
2175
+ this._options = e.map((t) => ({
2176
+ value: t.getAttribute("value") || t.textContent || "",
2177
+ label: t.textContent || "",
2178
+ disabled: t.hasAttribute("disabled"),
2179
+ element: t
2180
+ })), this._typeAhead = q(
2181
+ this._options.map((t) => t.label),
2182
+ { timeout: 500 }
2183
+ ), this.renderOptions(), this.updateTriggerText();
2184
+ }, this.handleTriggerClick = () => {
2185
+ var e;
2186
+ (e = this._triggerElement) != null && e.disabled || (this._open ? (this.open = !1, this._highlightedIndex = -1) : this.openAndHighlight());
2187
+ }, this.handleKeyDown = (e) => {
2188
+ var t;
2189
+ switch (e.key) {
2190
+ case "ArrowDown":
2191
+ e.preventDefault(), this._open ? this.highlightNext() : this.openAndHighlight();
2192
+ break;
2193
+ case "ArrowUp":
2194
+ e.preventDefault(), this._open ? this.highlightPrevious() : this.openAndHighlight(!0);
2195
+ break;
2196
+ case "Enter":
2197
+ if (e.preventDefault(), this._open && this._highlightedIndex >= 0) {
2198
+ const i = this._options[this._highlightedIndex];
2199
+ i && !i.disabled && this.selectOption(i);
2200
+ } else this._open || this.openAndHighlight();
2201
+ break;
2202
+ case " ":
2203
+ if (e.preventDefault(), this._open && this._highlightedIndex >= 0) {
2204
+ const i = this._options[this._highlightedIndex];
2205
+ i && !i.disabled && this.selectOption(i);
2206
+ } else this._open || this.openAndHighlight();
2207
+ break;
2208
+ case "Escape":
2209
+ e.preventDefault(), this._open && (this.open = !1, this._highlightedIndex = -1);
2210
+ break;
2211
+ case "Home":
2212
+ this._open && (e.preventDefault(), this._highlightedIndex = this.findFirstEnabled(), this.updateHighlight());
2213
+ break;
2214
+ case "End":
2215
+ this._open && (e.preventDefault(), this._highlightedIndex = this.findLastEnabled(), this.updateHighlight());
2216
+ break;
2217
+ case "Tab":
2218
+ this._open && (this.open = !1, this._highlightedIndex = -1);
2219
+ break;
2220
+ default:
2221
+ if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
2222
+ const i = (t = this._typeAhead) == null ? void 0 : t.type(e.key);
2223
+ if (i) {
2224
+ const s = this._options.findIndex(
2225
+ (a) => a.label === i && !a.disabled
2226
+ );
2227
+ s >= 0 && (this._open || (this.open = !0), this._highlightedIndex = s, this.updateHighlight());
2228
+ }
2229
+ }
2230
+ break;
2231
+ }
2232
+ }, this.handleBlur = () => {
2233
+ setTimeout(() => {
2234
+ var e;
2235
+ (e = this.shadowRoot) != null && e.activeElement || (this.open = !1, this._highlightedIndex = -1);
2236
+ }, 150);
2237
+ }, this.handleListboxMouseDown = (e) => {
2238
+ e.preventDefault();
2239
+ }, this.handleOptionClick = (e) => {
2240
+ const t = e.currentTarget, i = parseInt(t.dataset.index || "0", 10), s = this._options[i];
2241
+ s && !s.disabled && this.selectOption(s);
2242
+ }, this.handleOptionHover = (e) => {
2243
+ const t = e.currentTarget, i = parseInt(t.dataset.index || "0", 10), s = this._options[i];
2244
+ s && !s.disabled && (this._highlightedIndex = i, this.updateHighlight());
2245
+ }, this.handleOutsideClick = (e) => {
2246
+ if (!this._open) return;
2247
+ e.composedPath().includes(this) || (this.open = !1, this._highlightedIndex = -1);
2248
+ };
2249
+ }
2250
+ static get observedAttributes() {
2251
+ return ["open", "value", "placeholder", "disabled"];
2252
+ }
2253
+ get open() {
2254
+ return this._open;
2255
+ }
2256
+ set open(e) {
2257
+ const t = this._open;
2258
+ this._open = e, e !== t && this.updateListboxVisibility(), this.toggleAttribute("open", e);
2259
+ }
2260
+ get value() {
2261
+ return this._selectedValue;
2262
+ }
2263
+ set value(e) {
2264
+ this._selectedValue = e, this.updateTriggerText(), this.setAttribute("value", e || "");
2265
+ }
2266
+ setupAccessibility() {
710
2267
  }
711
2268
  render() {
712
- const t = this.attachShadow({ mode: "open" });
713
- t.innerHTML = `
714
- <style>${F}</style>
715
- <slot name="trigger"></slot>
716
- <div
717
- class="menu-content"
718
- role="menu"
719
- aria-labelledby="${this._id}-trigger"
720
- tabindex="-1"
721
- hidden
722
- part="menu"
723
- >
2269
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-trigger`, i = `${this._id}-listbox`, s = this.getAttribute("placeholder") || "Select an option...", a = this.getAttribute("aria-label") || "", r = this.getAttribute("aria-labelledby") || "";
2270
+ e.innerHTML = `
2271
+ <style>${xe}</style>
2272
+ <div class="select-wrapper" part="wrapper">
2273
+ <button
2274
+ id="${t}"
2275
+ type="button"
2276
+ role="combobox"
2277
+ aria-expanded="false"
2278
+ aria-controls="${i}"
2279
+ aria-haspopup="listbox"
2280
+ ${a ? `aria-label="${a}"` : ""}
2281
+ ${r ? `aria-labelledby="${r}"` : ""}
2282
+ class="select-trigger"
2283
+ part="trigger"
2284
+ >
2285
+ <span class="select-value placeholder" part="value">${s}</span>
2286
+ <span class="chevron" aria-hidden="true" part="chevron">&#9660;</span>
2287
+ </button>
2288
+ <ul
2289
+ id="${i}"
2290
+ role="listbox"
2291
+ aria-labelledby="${t}"
2292
+ class="listbox"
2293
+ tabindex="-1"
2294
+ hidden
2295
+ part="listbox"
2296
+ ></ul>
2297
+ </div>
2298
+ <div class="options-source" hidden>
724
2299
  <slot></slot>
725
2300
  </div>
726
- `;
2301
+ `, this._triggerElement = e.querySelector(".select-trigger"), this._listboxElement = e.querySelector(".listbox");
727
2302
  }
728
2303
  setupEventListeners() {
729
- var s, o;
730
- const t = this.querySelector('[slot="trigger"]');
731
- t == null || t.addEventListener("click", this.handleTriggerClick), t == null || t.addEventListener(
732
- "keydown",
733
- this.handleTriggerKeyDown
734
- );
735
- const e = (s = this.shadowRoot) == null ? void 0 : s.querySelector('slot[name="trigger"]');
736
- e == null || e.addEventListener("click", this.handleTriggerClick), this.addEventListener("click", this.handleItemClick), this.addEventListener("keydown", this.handleMenuKeyDown), this.addEventListener("mouseover", this.handleMouseOver), document.addEventListener("mousedown", this.handleOutsideClick);
737
- const i = (o = this.shadowRoot) == null ? void 0 : o.querySelector("slot:not([name])");
738
- i == null || i.addEventListener("slotchange", this.updateMenuItems), this.updateMenuItems();
2304
+ var t, i, s, a, r;
2305
+ (t = this._triggerElement) == null || t.addEventListener("click", this.handleTriggerClick), (i = this._triggerElement) == null || i.addEventListener("keydown", this.handleKeyDown), (s = this._triggerElement) == null || s.addEventListener("blur", this.handleBlur), (a = this._listboxElement) == null || a.addEventListener(
2306
+ "mousedown",
2307
+ this.handleListboxMouseDown
2308
+ ), document.addEventListener("mousedown", this.handleOutsideClick);
2309
+ const e = (r = this.shadowRoot) == null ? void 0 : r.querySelector("slot");
2310
+ e == null || e.addEventListener("slotchange", this.updateOptions), this.updateOptions();
739
2311
  }
740
2312
  cleanupEventListeners() {
741
2313
  document.removeEventListener("mousedown", this.handleOutsideClick);
742
2314
  }
743
- onAttributeChange(t, e, i) {
744
- t === "open" && (this.open = i !== null);
2315
+ onAttributeChange(e, t, i) {
2316
+ e === "open" && (this.open = i !== null), e === "value" && (this.value = i), e === "disabled" && this._triggerElement && (this._triggerElement.disabled = i !== null), e === "placeholder" && this.updateTriggerText();
2317
+ }
2318
+ renderOptions() {
2319
+ this._listboxElement && (this._listboxElement.innerHTML = this._options.map(
2320
+ (e, t) => `
2321
+ <li
2322
+ id="${this._id}-option-${t}"
2323
+ role="option"
2324
+ aria-selected="${this._selectedValue === e.value}"
2325
+ aria-disabled="${e.disabled}"
2326
+ data-value="${e.value}"
2327
+ data-index="${t}"
2328
+ part="option"
2329
+ ${e.disabled ? 'class="disabled"' : ""}
2330
+ >
2331
+ <span class="option-text">${e.label}</span>
2332
+ ${this._selectedValue === e.value ? '<span class="check-mark" aria-hidden="true">&#10003;</span>' : ""}
2333
+ </li>
2334
+ `
2335
+ ).join(""), this._listboxElement.querySelectorAll('[role="option"]').forEach((e) => {
2336
+ e.addEventListener("click", this.handleOptionClick), e.addEventListener("mouseenter", this.handleOptionHover);
2337
+ }));
2338
+ }
2339
+ openAndHighlight(e = !1) {
2340
+ this.open = !0;
2341
+ const t = this._options.findIndex(
2342
+ (i) => i.value === this._selectedValue
2343
+ );
2344
+ t >= 0 ? this._highlightedIndex = t : this._highlightedIndex = e ? this.findLastEnabled() : this.findFirstEnabled(), this.updateHighlight(), v(
2345
+ `${this._options.length} option${this._options.length === 1 ? "" : "s"} available`
2346
+ );
2347
+ }
2348
+ selectOption(e) {
2349
+ this._selectedValue = e.value, this.updateTriggerText(), this.open = !1, this._highlightedIndex = -1, this.renderOptions(), v(`${e.label} selected`), this.emit("a11y-select-change", {
2350
+ value: e.value,
2351
+ label: e.label
2352
+ }), this.emit("change", {
2353
+ value: e.value,
2354
+ label: e.label
2355
+ });
745
2356
  }
746
- highlightItem(t, e = !0) {
2357
+ updateTriggerText() {
747
2358
  var s;
748
- if (this._highlightedIndex >= 0) {
749
- const o = this._menuItems[this._highlightedIndex];
750
- o == null || o.removeAttribute("data-highlighted");
2359
+ const e = (s = this.shadowRoot) == null ? void 0 : s.querySelector(".select-value");
2360
+ if (!e) return;
2361
+ const t = this._options.find(
2362
+ (a) => a.value === this._selectedValue
2363
+ ), i = this.getAttribute("placeholder") || "Select an option...";
2364
+ t ? (e.textContent = t.label, e.classList.remove("placeholder")) : (e.textContent = i, e.classList.add("placeholder"));
2365
+ }
2366
+ highlightNext() {
2367
+ const e = this.findNextEnabled(this._highlightedIndex, 1);
2368
+ e >= 0 && (this._highlightedIndex = e, this.updateHighlight());
2369
+ }
2370
+ highlightPrevious() {
2371
+ const e = this.findNextEnabled(this._highlightedIndex, -1);
2372
+ e >= 0 && (this._highlightedIndex = e, this.updateHighlight());
2373
+ }
2374
+ findNextEnabled(e, t) {
2375
+ var r;
2376
+ const i = this._options.length;
2377
+ let s = e + t;
2378
+ s < 0 && (s = i - 1), s >= i && (s = 0);
2379
+ const a = s;
2380
+ for (; (r = this._options[s]) != null && r.disabled; )
2381
+ if (s += t, s < 0 && (s = i - 1), s >= i && (s = 0), s === a) return -1;
2382
+ return s;
2383
+ }
2384
+ findFirstEnabled() {
2385
+ return this._options.findIndex((e) => !e.disabled);
2386
+ }
2387
+ findLastEnabled() {
2388
+ var e;
2389
+ for (let t = this._options.length - 1; t >= 0; t--)
2390
+ if (!((e = this._options[t]) != null && e.disabled)) return t;
2391
+ return -1;
2392
+ }
2393
+ updateHighlight() {
2394
+ var e, t, i, s;
2395
+ if ((e = this._listboxElement) == null || e.querySelectorAll('[role="option"]').forEach((a, r) => {
2396
+ a.classList.toggle("highlighted", r === this._highlightedIndex);
2397
+ }), this._highlightedIndex >= 0) {
2398
+ const a = `${this._id}-option-${this._highlightedIndex}`;
2399
+ (t = this._triggerElement) == null || t.setAttribute("aria-activedescendant", a);
2400
+ const r = (i = this._listboxElement) == null ? void 0 : i.querySelector(`#${a}`);
2401
+ r == null || r.scrollIntoView({ block: "nearest", behavior: "smooth" });
2402
+ } else
2403
+ (s = this._triggerElement) == null || s.removeAttribute("aria-activedescendant");
2404
+ }
2405
+ updateListboxVisibility() {
2406
+ !this._listboxElement || !this._triggerElement || (this._open ? (this._listboxElement.hidden = !1, this._triggerElement.setAttribute("aria-expanded", "true"), this.updateListboxPosition(), this.emit("a11y-select-open")) : (this._listboxElement.hidden = !0, this._triggerElement.setAttribute("aria-expanded", "false"), this._highlightedIndex = -1, this.updateHighlight(), this._listboxElement.style.top = "", this._listboxElement.style.bottom = "", this.removeAttribute("data-position"), this.emit("a11y-select-close")));
2407
+ }
2408
+ updateListboxPosition() {
2409
+ if (!this._listboxElement || !this._triggerElement) return;
2410
+ const e = this._triggerElement.getBoundingClientRect(), t = window.innerHeight, i = Math.min(this._listboxElement.scrollHeight, 200), s = t - e.bottom, a = e.top;
2411
+ s < i + 8 && a > s ? (this._listboxElement.style.top = "auto", this._listboxElement.style.bottom = "100%", this._listboxElement.style.marginTop = "0", this._listboxElement.style.marginBottom = "4px", this.setAttribute("data-position", "top")) : (this._listboxElement.style.top = "100%", this._listboxElement.style.bottom = "auto", this._listboxElement.style.marginTop = "4px", this._listboxElement.style.marginBottom = "0", this.setAttribute("data-position", "bottom"));
2412
+ }
2413
+ /** Programmatic open */
2414
+ show() {
2415
+ this.open = !0;
2416
+ }
2417
+ /** Programmatic close */
2418
+ close() {
2419
+ this.open = !1;
2420
+ }
2421
+ }
2422
+ u("a11y-select", j);
2423
+ class U extends c {
2424
+ constructor() {
2425
+ super(...arguments), this._value = "", this._inputEl = null, this._labelEl = null, this._hintEl = null, this._errorEl = null, this.handleInput = (e) => {
2426
+ const t = e.target;
2427
+ this._value = t.value, this.emit("input", { value: this._value });
2428
+ }, this.handleChange = (e) => {
2429
+ const t = e.target;
2430
+ this._value = t.value, this.emit("change", { value: this._value });
2431
+ }, this.handleFocus = () => {
2432
+ this.emit("a11y-input-focus");
2433
+ }, this.handleBlur = () => {
2434
+ this.emit("a11y-input-blur");
2435
+ };
2436
+ }
2437
+ static get observedAttributes() {
2438
+ return [
2439
+ "label",
2440
+ "hint",
2441
+ "error",
2442
+ "type",
2443
+ "placeholder",
2444
+ "value",
2445
+ "disabled",
2446
+ "readonly",
2447
+ "required",
2448
+ "name",
2449
+ "autocomplete",
2450
+ "maxlength",
2451
+ "minlength",
2452
+ "pattern",
2453
+ "inputmode",
2454
+ "aria-label",
2455
+ "aria-labelledby"
2456
+ ];
2457
+ }
2458
+ // =========================================================================
2459
+ // Properties
2460
+ // =========================================================================
2461
+ get value() {
2462
+ return this._value;
2463
+ }
2464
+ set value(e) {
2465
+ const t = this._value;
2466
+ this._value = e, this._inputEl && this._inputEl.value !== e && (this._inputEl.value = e), e !== t && this.setAttribute("value", e);
2467
+ }
2468
+ get disabled() {
2469
+ return this.hasAttribute("disabled");
2470
+ }
2471
+ set disabled(e) {
2472
+ this.toggleAttribute("disabled", e);
2473
+ }
2474
+ get readOnly() {
2475
+ return this.hasAttribute("readonly");
2476
+ }
2477
+ set readOnly(e) {
2478
+ this.toggleAttribute("readonly", e);
2479
+ }
2480
+ get required() {
2481
+ return this.hasAttribute("required");
2482
+ }
2483
+ set required(e) {
2484
+ this.toggleAttribute("required", e);
2485
+ }
2486
+ get error() {
2487
+ return this.getAttribute("error") || "";
2488
+ }
2489
+ set error(e) {
2490
+ e ? this.setAttribute("error", e) : this.removeAttribute("error");
2491
+ }
2492
+ // =========================================================================
2493
+ // Lifecycle
2494
+ // =========================================================================
2495
+ setupAccessibility() {
2496
+ var e;
2497
+ typeof process < "u" && ((e = process.env) == null ? void 0 : e.NODE_ENV) !== "production" && (this.hasAttribute("label") || this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby") || console.warn(
2498
+ `[compa11y/Input] Input has no accessible label. Add label="...", aria-label="...", or aria-labelledby="..." attribute.
2499
+ 💡 Suggestion: <a11y-input label="Full Name"></a11y-input>`
2500
+ ));
2501
+ }
2502
+ render() {
2503
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-field`, i = `${this._id}-label`, s = `${this._id}-hint`, a = `${this._id}-error`, r = this.getAttribute("label") || "", l = this.getAttribute("hint") || "", o = this.getAttribute("error") || "", d = this.getAttribute("type") || "text", h = this.getAttribute("placeholder") || "", g = this.getAttribute("name") || "", m = this.getAttribute("autocomplete") || "", f = this.getAttribute("maxlength"), _ = this.getAttribute("minlength"), k = this.getAttribute("pattern"), w = this.getAttribute("inputmode"), L = this.getAttribute("aria-label") || "", S = this.getAttribute("aria-labelledby") || "", I = this.disabled, x = this.readOnly, y = this.required, A = !!o, E = [];
2504
+ l && E.push(s), A && E.push(a);
2505
+ const C = E.length ? `aria-describedby="${E.join(" ")}"` : "", $ = !r && L ? `aria-label="${L}"` : "", ee = !r && S ? `aria-labelledby="${S}"` : r ? `aria-labelledby="${i}"` : "";
2506
+ this.setAttribute("data-error", A ? "true" : "false"), e.innerHTML = `
2507
+ <style>${Ee}</style>
2508
+ <div class="input-wrapper" part="wrapper">
2509
+ ${r ? `<label id="${i}" for="${t}" class="input-label" part="label">
2510
+ ${r}${y ? '<span class="input-required" aria-hidden="true" part="required">*</span>' : ""}
2511
+ </label>` : ""}
2512
+ <input
2513
+ id="${t}"
2514
+ type="${d}"
2515
+ value="${this._value}"
2516
+ ${h ? `placeholder="${h}"` : ""}
2517
+ ${g ? `name="${g}"` : ""}
2518
+ ${m ? `autocomplete="${m}"` : ""}
2519
+ ${f ? `maxlength="${f}"` : ""}
2520
+ ${_ ? `minlength="${_}"` : ""}
2521
+ ${k ? `pattern="${k}"` : ""}
2522
+ ${w ? `inputmode="${w}"` : ""}
2523
+ ${$}
2524
+ ${ee}
2525
+ ${C}
2526
+ ${A ? 'aria-invalid="true"' : ""}
2527
+ ${y ? 'aria-required="true"' : ""}
2528
+ ${I ? "disabled" : ""}
2529
+ ${x ? "readonly" : ""}
2530
+ part="field"
2531
+ />
2532
+ ${l ? `<div id="${s}" class="input-hint" part="hint">${l}</div>` : ""}
2533
+ ${A ? `<div id="${a}" class="input-error" role="alert" part="error">${o}</div>` : ""}
2534
+ </div>
2535
+ `, this._inputEl = e.querySelector("input"), this._labelEl = e.querySelector("label"), this._hintEl = e.querySelector(".input-hint"), this._errorEl = e.querySelector(".input-error");
2536
+ const z = this.getAttribute("value");
2537
+ z && this._inputEl && (this._value = z, this._inputEl.value = z);
2538
+ }
2539
+ setupEventListeners() {
2540
+ var e, t, i, s;
2541
+ (e = this._inputEl) == null || e.addEventListener("input", this.handleInput), (t = this._inputEl) == null || t.addEventListener("change", this.handleChange), (i = this._inputEl) == null || i.addEventListener("focus", this.handleFocus), (s = this._inputEl) == null || s.addEventListener("blur", this.handleBlur);
2542
+ }
2543
+ cleanupEventListeners() {
2544
+ var e, t, i, s;
2545
+ (e = this._inputEl) == null || e.removeEventListener("input", this.handleInput), (t = this._inputEl) == null || t.removeEventListener("change", this.handleChange), (i = this._inputEl) == null || i.removeEventListener("focus", this.handleFocus), (s = this._inputEl) == null || s.removeEventListener("blur", this.handleBlur);
2546
+ }
2547
+ onAttributeChange(e, t, i) {
2548
+ switch (e) {
2549
+ case "value":
2550
+ this._value = i || "", this._inputEl && this._inputEl.value !== this._value && (this._inputEl.value = this._value);
2551
+ break;
2552
+ case "error":
2553
+ this.updateError(i || "");
2554
+ break;
2555
+ case "hint":
2556
+ this.updateHint(i || "");
2557
+ break;
2558
+ case "disabled":
2559
+ this._inputEl && (i !== null ? this._inputEl.setAttribute("disabled", "") : this._inputEl.removeAttribute("disabled"));
2560
+ break;
2561
+ case "readonly":
2562
+ this._inputEl && (i !== null ? this._inputEl.setAttribute("readonly", "") : this._inputEl.removeAttribute("readonly"));
2563
+ break;
2564
+ case "required":
2565
+ this._inputEl && (i !== null ? this._inputEl.setAttribute("aria-required", "true") : this._inputEl.removeAttribute("aria-required")), this.updateRequiredIndicator(i !== null);
2566
+ break;
2567
+ case "placeholder":
2568
+ this._inputEl && (i ? this._inputEl.setAttribute("placeholder", i) : this._inputEl.removeAttribute("placeholder"));
2569
+ break;
2570
+ case "type":
2571
+ this._inputEl && (this._inputEl.type = i || "text");
2572
+ break;
2573
+ case "name":
2574
+ this._inputEl && (i ? this._inputEl.setAttribute("name", i) : this._inputEl.removeAttribute("name"));
2575
+ break;
2576
+ case "autocomplete":
2577
+ this._inputEl && (i ? this._inputEl.setAttribute("autocomplete", i) : this._inputEl.removeAttribute("autocomplete"));
2578
+ break;
2579
+ case "maxlength":
2580
+ this._inputEl && (i ? this._inputEl.setAttribute("maxlength", i) : this._inputEl.removeAttribute("maxlength"));
2581
+ break;
2582
+ case "minlength":
2583
+ this._inputEl && (i ? this._inputEl.setAttribute("minlength", i) : this._inputEl.removeAttribute("minlength"));
2584
+ break;
2585
+ case "pattern":
2586
+ this._inputEl && (i ? this._inputEl.setAttribute("pattern", i) : this._inputEl.removeAttribute("pattern"));
2587
+ break;
2588
+ case "inputmode":
2589
+ this._inputEl && (i ? this._inputEl.setAttribute("inputmode", i) : this._inputEl.removeAttribute("inputmode"));
2590
+ break;
2591
+ case "label":
2592
+ case "aria-label":
2593
+ case "aria-labelledby":
2594
+ this.shadowRoot && (this.cleanupEventListeners(), this.shadowRoot.innerHTML = "", this.render(), this.setupEventListeners());
2595
+ break;
751
2596
  }
752
- this._highlightedIndex = t;
753
- const i = this._menuItems[t];
754
- if (i) {
755
- i.setAttribute("data-highlighted", "true"), e && i.focus();
756
- const o = (s = this.shadowRoot) == null ? void 0 : s.querySelector('[role="menu"]');
757
- o == null || o.setAttribute("aria-activedescendant", i.id);
2597
+ }
2598
+ // =========================================================================
2599
+ // DOM update helpers
2600
+ // =========================================================================
2601
+ updateError(e) {
2602
+ var i;
2603
+ const t = !!e;
2604
+ if (this.setAttribute("data-error", t ? "true" : "false"), this._inputEl && (t ? this._inputEl.setAttribute("aria-invalid", "true") : this._inputEl.removeAttribute("aria-invalid")), t) {
2605
+ if (this._errorEl)
2606
+ this._errorEl.textContent = e;
2607
+ else {
2608
+ const s = `${this._id}-error`, a = document.createElement("div");
2609
+ a.id = s, a.className = "input-error", a.setAttribute("role", "alert"), a.setAttribute("part", "error"), a.textContent = e;
2610
+ const r = (i = this.shadowRoot) == null ? void 0 : i.querySelector(".input-wrapper");
2611
+ r == null || r.appendChild(a), this._errorEl = a, D(e);
2612
+ }
2613
+ this.updateAriaDescribedBy();
2614
+ } else
2615
+ this._errorEl && (this._errorEl.remove(), this._errorEl = null), this.updateAriaDescribedBy();
2616
+ }
2617
+ updateHint(e) {
2618
+ var t;
2619
+ if (e)
2620
+ if (this._hintEl)
2621
+ this._hintEl.textContent = e;
2622
+ else {
2623
+ const i = `${this._id}-hint`, s = document.createElement("div");
2624
+ s.id = i, s.className = "input-hint", s.setAttribute("part", "hint"), s.textContent = e;
2625
+ const a = (t = this.shadowRoot) == null ? void 0 : t.querySelector(".input-wrapper");
2626
+ this._errorEl ? a == null || a.insertBefore(s, this._errorEl) : a == null || a.appendChild(s), this._hintEl = s;
2627
+ }
2628
+ else
2629
+ this._hintEl && (this._hintEl.remove(), this._hintEl = null);
2630
+ this.updateAriaDescribedBy();
2631
+ }
2632
+ updateAriaDescribedBy() {
2633
+ if (!this._inputEl) return;
2634
+ const e = [];
2635
+ this._hintEl && e.push(this._hintEl.id), this._errorEl && e.push(this._errorEl.id), e.length > 0 ? this._inputEl.setAttribute("aria-describedby", e.join(" ")) : this._inputEl.removeAttribute("aria-describedby");
2636
+ }
2637
+ updateRequiredIndicator(e) {
2638
+ if (!this._labelEl) return;
2639
+ const t = this._labelEl.querySelector(".input-required");
2640
+ if (e && !t) {
2641
+ const i = document.createElement("span");
2642
+ i.className = "input-required", i.setAttribute("aria-hidden", "true"), i.setAttribute("part", "required"), i.textContent = "*", this._labelEl.appendChild(i);
2643
+ } else !e && t && t.remove();
2644
+ }
2645
+ // =========================================================================
2646
+ // Public methods
2647
+ // =========================================================================
2648
+ /** Focus the input element */
2649
+ focus() {
2650
+ var e;
2651
+ (e = this._inputEl) == null || e.focus();
2652
+ }
2653
+ /** Blur the input element */
2654
+ blur() {
2655
+ var e;
2656
+ (e = this._inputEl) == null || e.blur();
2657
+ }
2658
+ /** Select all text in the input */
2659
+ select() {
2660
+ var e;
2661
+ (e = this._inputEl) == null || e.select();
2662
+ }
2663
+ }
2664
+ u("a11y-input", U);
2665
+ class Y extends c {
2666
+ constructor() {
2667
+ super(...arguments), this._value = "", this._textareaEl = null, this._labelEl = null, this._hintEl = null, this._errorEl = null, this.handleInput = (e) => {
2668
+ const t = e.target;
2669
+ this._value = t.value, this.emit("input", { value: this._value });
2670
+ }, this.handleChange = (e) => {
2671
+ const t = e.target;
2672
+ this._value = t.value, this.emit("change", { value: this._value });
2673
+ }, this.handleFocus = () => {
2674
+ this.emit("a11y-textarea-focus");
2675
+ }, this.handleBlur = () => {
2676
+ this.emit("a11y-textarea-blur");
2677
+ };
2678
+ }
2679
+ static get observedAttributes() {
2680
+ return [
2681
+ "label",
2682
+ "hint",
2683
+ "error",
2684
+ "rows",
2685
+ "resize",
2686
+ "placeholder",
2687
+ "value",
2688
+ "disabled",
2689
+ "readonly",
2690
+ "required",
2691
+ "name",
2692
+ "autocomplete",
2693
+ "maxlength",
2694
+ "minlength",
2695
+ "aria-label",
2696
+ "aria-labelledby"
2697
+ ];
2698
+ }
2699
+ // =========================================================================
2700
+ // Properties
2701
+ // =========================================================================
2702
+ get value() {
2703
+ return this._value;
2704
+ }
2705
+ set value(e) {
2706
+ const t = this._value;
2707
+ this._value = e, this._textareaEl && this._textareaEl.value !== e && (this._textareaEl.value = e), e !== t && this.setAttribute("value", e);
2708
+ }
2709
+ get disabled() {
2710
+ return this.hasAttribute("disabled");
2711
+ }
2712
+ set disabled(e) {
2713
+ this.toggleAttribute("disabled", e);
2714
+ }
2715
+ get readOnly() {
2716
+ return this.hasAttribute("readonly");
2717
+ }
2718
+ set readOnly(e) {
2719
+ this.toggleAttribute("readonly", e);
2720
+ }
2721
+ get required() {
2722
+ return this.hasAttribute("required");
2723
+ }
2724
+ set required(e) {
2725
+ this.toggleAttribute("required", e);
2726
+ }
2727
+ get error() {
2728
+ return this.getAttribute("error") || "";
2729
+ }
2730
+ set error(e) {
2731
+ e ? this.setAttribute("error", e) : this.removeAttribute("error");
2732
+ }
2733
+ // =========================================================================
2734
+ // Lifecycle
2735
+ // =========================================================================
2736
+ setupAccessibility() {
2737
+ var e;
2738
+ typeof process < "u" && ((e = process.env) == null ? void 0 : e.NODE_ENV) !== "production" && (this.hasAttribute("label") || this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby") || console.warn(
2739
+ `[compa11y/Textarea] Textarea has no accessible label. Add label="...", aria-label="...", or aria-labelledby="..." attribute.
2740
+ 💡 Suggestion: <a11y-textarea label="Description"></a11y-textarea>`
2741
+ ));
2742
+ }
2743
+ render() {
2744
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-field`, i = `${this._id}-label`, s = `${this._id}-hint`, a = `${this._id}-error`, r = this.getAttribute("label") || "", l = this.getAttribute("hint") || "", o = this.getAttribute("error") || "", d = this.getAttribute("rows") || "3", h = this.getAttribute("placeholder") || "", g = this.getAttribute("name") || "", m = this.getAttribute("autocomplete") || "", f = this.getAttribute("maxlength"), _ = this.getAttribute("minlength"), k = this.getAttribute("aria-label") || "", w = this.getAttribute("aria-labelledby") || "", L = this.disabled, S = this.readOnly, I = this.required, x = !!o, y = [];
2745
+ l && y.push(s), x && y.push(a);
2746
+ const A = y.length ? `aria-describedby="${y.join(" ")}"` : "", E = !r && k ? `aria-label="${k}"` : "", C = !r && w ? `aria-labelledby="${w}"` : r ? `aria-labelledby="${i}"` : "";
2747
+ this.setAttribute("data-error", x ? "true" : "false"), e.innerHTML = `
2748
+ <style>${ke}</style>
2749
+ <div class="textarea-wrapper" part="wrapper">
2750
+ ${r ? `<label id="${i}" for="${t}" class="textarea-label" part="label">
2751
+ ${r}${I ? '<span class="textarea-required" aria-hidden="true" part="required">*</span>' : ""}
2752
+ </label>` : ""}
2753
+ <textarea
2754
+ id="${t}"
2755
+ rows="${d}"
2756
+ ${h ? `placeholder="${h}"` : ""}
2757
+ ${g ? `name="${g}"` : ""}
2758
+ ${m ? `autocomplete="${m}"` : ""}
2759
+ ${f ? `maxlength="${f}"` : ""}
2760
+ ${_ ? `minlength="${_}"` : ""}
2761
+ ${E}
2762
+ ${C}
2763
+ ${A}
2764
+ ${x ? 'aria-invalid="true"' : ""}
2765
+ ${I ? 'aria-required="true"' : ""}
2766
+ ${L ? "disabled" : ""}
2767
+ ${S ? "readonly" : ""}
2768
+ part="field"
2769
+ >${this._value}</textarea>
2770
+ ${l ? `<div id="${s}" class="textarea-hint" part="hint">${l}</div>` : ""}
2771
+ ${x ? `<div id="${a}" class="textarea-error" role="alert" part="error">${o}</div>` : ""}
2772
+ </div>
2773
+ `, this._textareaEl = e.querySelector("textarea"), this._labelEl = e.querySelector("label"), this._hintEl = e.querySelector(".textarea-hint"), this._errorEl = e.querySelector(".textarea-error");
2774
+ const $ = this.getAttribute("value");
2775
+ $ && this._textareaEl && (this._value = $, this._textareaEl.value = $);
2776
+ }
2777
+ setupEventListeners() {
2778
+ var e, t, i, s;
2779
+ (e = this._textareaEl) == null || e.addEventListener("input", this.handleInput), (t = this._textareaEl) == null || t.addEventListener("change", this.handleChange), (i = this._textareaEl) == null || i.addEventListener("focus", this.handleFocus), (s = this._textareaEl) == null || s.addEventListener("blur", this.handleBlur);
2780
+ }
2781
+ cleanupEventListeners() {
2782
+ var e, t, i, s;
2783
+ (e = this._textareaEl) == null || e.removeEventListener("input", this.handleInput), (t = this._textareaEl) == null || t.removeEventListener("change", this.handleChange), (i = this._textareaEl) == null || i.removeEventListener("focus", this.handleFocus), (s = this._textareaEl) == null || s.removeEventListener("blur", this.handleBlur);
2784
+ }
2785
+ onAttributeChange(e, t, i) {
2786
+ switch (e) {
2787
+ case "value":
2788
+ this._value = i || "", this._textareaEl && this._textareaEl.value !== this._value && (this._textareaEl.value = this._value);
2789
+ break;
2790
+ case "error":
2791
+ this.updateError(i || "");
2792
+ break;
2793
+ case "hint":
2794
+ this.updateHint(i || "");
2795
+ break;
2796
+ case "disabled":
2797
+ this._textareaEl && (i !== null ? this._textareaEl.setAttribute("disabled", "") : this._textareaEl.removeAttribute("disabled"));
2798
+ break;
2799
+ case "readonly":
2800
+ this._textareaEl && (i !== null ? this._textareaEl.setAttribute("readonly", "") : this._textareaEl.removeAttribute("readonly"));
2801
+ break;
2802
+ case "required":
2803
+ this._textareaEl && (i !== null ? this._textareaEl.setAttribute("aria-required", "true") : this._textareaEl.removeAttribute("aria-required")), this.updateRequiredIndicator(i !== null);
2804
+ break;
2805
+ case "placeholder":
2806
+ this._textareaEl && (i ? this._textareaEl.setAttribute("placeholder", i) : this._textareaEl.removeAttribute("placeholder"));
2807
+ break;
2808
+ case "rows":
2809
+ this._textareaEl && (this._textareaEl.rows = parseInt(i || "3", 10));
2810
+ break;
2811
+ case "name":
2812
+ this._textareaEl && (i ? this._textareaEl.setAttribute("name", i) : this._textareaEl.removeAttribute("name"));
2813
+ break;
2814
+ case "autocomplete":
2815
+ this._textareaEl && (i ? this._textareaEl.setAttribute("autocomplete", i) : this._textareaEl.removeAttribute("autocomplete"));
2816
+ break;
2817
+ case "maxlength":
2818
+ this._textareaEl && (i ? this._textareaEl.setAttribute("maxlength", i) : this._textareaEl.removeAttribute("maxlength"));
2819
+ break;
2820
+ case "minlength":
2821
+ this._textareaEl && (i ? this._textareaEl.setAttribute("minlength", i) : this._textareaEl.removeAttribute("minlength"));
2822
+ break;
2823
+ case "resize":
2824
+ this._textareaEl && (this._textareaEl.style.resize = i || "vertical");
2825
+ break;
2826
+ case "label":
2827
+ case "aria-label":
2828
+ case "aria-labelledby":
2829
+ this.shadowRoot && (this.cleanupEventListeners(), this.shadowRoot.innerHTML = "", this.render(), this.setupEventListeners());
2830
+ break;
2831
+ }
2832
+ }
2833
+ // =========================================================================
2834
+ // DOM update helpers
2835
+ // =========================================================================
2836
+ updateError(e) {
2837
+ var i;
2838
+ const t = !!e;
2839
+ if (this.setAttribute("data-error", t ? "true" : "false"), this._textareaEl && (t ? this._textareaEl.setAttribute("aria-invalid", "true") : this._textareaEl.removeAttribute("aria-invalid")), t) {
2840
+ if (this._errorEl)
2841
+ this._errorEl.textContent = e;
2842
+ else {
2843
+ const s = `${this._id}-error`, a = document.createElement("div");
2844
+ a.id = s, a.className = "textarea-error", a.setAttribute("role", "alert"), a.setAttribute("part", "error"), a.textContent = e;
2845
+ const r = (i = this.shadowRoot) == null ? void 0 : i.querySelector(".textarea-wrapper");
2846
+ r == null || r.appendChild(a), this._errorEl = a, D(e);
2847
+ }
2848
+ this.updateAriaDescribedBy();
2849
+ } else
2850
+ this._errorEl && (this._errorEl.remove(), this._errorEl = null), this.updateAriaDescribedBy();
2851
+ }
2852
+ updateHint(e) {
2853
+ var t;
2854
+ if (e)
2855
+ if (this._hintEl)
2856
+ this._hintEl.textContent = e;
2857
+ else {
2858
+ const i = `${this._id}-hint`, s = document.createElement("div");
2859
+ s.id = i, s.className = "textarea-hint", s.setAttribute("part", "hint"), s.textContent = e;
2860
+ const a = (t = this.shadowRoot) == null ? void 0 : t.querySelector(".textarea-wrapper");
2861
+ this._errorEl ? a == null || a.insertBefore(s, this._errorEl) : a == null || a.appendChild(s), this._hintEl = s;
2862
+ }
2863
+ else
2864
+ this._hintEl && (this._hintEl.remove(), this._hintEl = null);
2865
+ this.updateAriaDescribedBy();
2866
+ }
2867
+ updateAriaDescribedBy() {
2868
+ if (!this._textareaEl) return;
2869
+ const e = [];
2870
+ this._hintEl && e.push(this._hintEl.id), this._errorEl && e.push(this._errorEl.id), e.length > 0 ? this._textareaEl.setAttribute("aria-describedby", e.join(" ")) : this._textareaEl.removeAttribute("aria-describedby");
2871
+ }
2872
+ updateRequiredIndicator(e) {
2873
+ if (!this._labelEl) return;
2874
+ const t = this._labelEl.querySelector(".textarea-required");
2875
+ if (e && !t) {
2876
+ const i = document.createElement("span");
2877
+ i.className = "textarea-required", i.setAttribute("aria-hidden", "true"), i.setAttribute("part", "required"), i.textContent = "*", this._labelEl.appendChild(i);
2878
+ } else !e && t && t.remove();
2879
+ }
2880
+ // =========================================================================
2881
+ // Public methods
2882
+ // =========================================================================
2883
+ /** Focus the textarea element */
2884
+ focus() {
2885
+ var e;
2886
+ (e = this._textareaEl) == null || e.focus();
2887
+ }
2888
+ /** Blur the textarea element */
2889
+ blur() {
2890
+ var e;
2891
+ (e = this._textareaEl) == null || e.blur();
2892
+ }
2893
+ /** Select all text in the textarea */
2894
+ select() {
2895
+ var e;
2896
+ (e = this._textareaEl) == null || e.select();
2897
+ }
2898
+ }
2899
+ u("a11y-textarea", Y);
2900
+ class G extends c {
2901
+ constructor() {
2902
+ super(...arguments), this._buttonEl = null, this.handleClick = (e) => {
2903
+ if (this.disabled || this.loading) {
2904
+ e.preventDefault(), e.stopPropagation();
2905
+ return;
2906
+ }
2907
+ this.emit("a11y-button-click");
2908
+ };
2909
+ }
2910
+ static get observedAttributes() {
2911
+ return [
2912
+ "variant",
2913
+ "size",
2914
+ "disabled",
2915
+ "discoverable",
2916
+ "loading",
2917
+ "type",
2918
+ "aria-label"
2919
+ ];
2920
+ }
2921
+ // =========================================================================
2922
+ // Properties
2923
+ // =========================================================================
2924
+ get disabled() {
2925
+ return this.hasAttribute("disabled");
2926
+ }
2927
+ set disabled(e) {
2928
+ this.toggleAttribute("disabled", e);
2929
+ }
2930
+ get discoverable() {
2931
+ return this.hasAttribute("discoverable");
2932
+ }
2933
+ set discoverable(e) {
2934
+ this.toggleAttribute("discoverable", e);
2935
+ }
2936
+ get loading() {
2937
+ return this.hasAttribute("loading");
2938
+ }
2939
+ set loading(e) {
2940
+ this.toggleAttribute("loading", e);
2941
+ }
2942
+ get variant() {
2943
+ return this.getAttribute("variant") || "secondary";
2944
+ }
2945
+ set variant(e) {
2946
+ this.setAttribute("variant", e);
2947
+ }
2948
+ get size() {
2949
+ return this.getAttribute("size") || "md";
2950
+ }
2951
+ set size(e) {
2952
+ this.setAttribute("size", e);
2953
+ }
2954
+ // =========================================================================
2955
+ // Lifecycle
2956
+ // =========================================================================
2957
+ setupAccessibility() {
2958
+ var e, t;
2959
+ typeof process < "u" && ((e = process.env) == null ? void 0 : e.NODE_ENV) !== "production" && ((t = this.textContent) != null && t.trim() || this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby") || console.warn(
2960
+ `[compa11y/Button] Button has no accessible label. Add text content, aria-label="...", or aria-labelledby="..." attribute.
2961
+ 💡 Suggestion: <a11y-button>Click me</a11y-button>`
2962
+ ));
2963
+ }
2964
+ render() {
2965
+ const e = this.attachShadow({ mode: "open" }), t = this.variant, i = this.size, s = this.getAttribute("type") || "button", a = this.getAttribute("aria-label") || "", r = this.disabled, l = this.discoverable, o = this.loading, d = r || o, h = r && !l;
2966
+ e.innerHTML = `
2967
+ <style>${we}</style>
2968
+ <button
2969
+ class="variant-${t} size-${i}"
2970
+ type="${s}"
2971
+ ${h ? "disabled" : ""}
2972
+ ${d ? 'aria-disabled="true"' : ""}
2973
+ ${o ? 'aria-busy="true"' : ""}
2974
+ ${a ? `aria-label="${a}"` : ""}
2975
+ part="button"
2976
+ >${o ? '<span class="button-spinner" aria-hidden="true" part="spinner"></span>' : ""}<slot></slot></button>
2977
+ `, this._buttonEl = e.querySelector("button");
2978
+ }
2979
+ setupEventListeners() {
2980
+ var e;
2981
+ (e = this._buttonEl) == null || e.addEventListener("click", this.handleClick);
2982
+ }
2983
+ cleanupEventListeners() {
2984
+ var e;
2985
+ (e = this._buttonEl) == null || e.removeEventListener("click", this.handleClick);
2986
+ }
2987
+ onAttributeChange(e, t, i) {
2988
+ switch (e) {
2989
+ case "variant": {
2990
+ if (!this._buttonEl) break;
2991
+ const a = this._buttonEl.className.split(" ").filter((r) => !r.startsWith("variant-"));
2992
+ a.push(`variant-${i || "secondary"}`), this._buttonEl.className = a.join(" ");
2993
+ break;
2994
+ }
2995
+ case "size": {
2996
+ if (!this._buttonEl) break;
2997
+ const a = this._buttonEl.className.split(" ").filter((r) => !r.startsWith("size-"));
2998
+ a.push(`size-${i || "md"}`), this._buttonEl.className = a.join(" ");
2999
+ break;
3000
+ }
3001
+ case "disabled":
3002
+ case "discoverable":
3003
+ this.updateDisabledState();
3004
+ break;
3005
+ case "loading":
3006
+ this.updateLoadingState();
3007
+ break;
3008
+ case "type":
3009
+ this._buttonEl && (this._buttonEl.type = i || "button");
3010
+ break;
3011
+ case "aria-label":
3012
+ this._buttonEl && (i ? this._buttonEl.setAttribute("aria-label", i) : this._buttonEl.removeAttribute("aria-label"));
3013
+ break;
3014
+ }
3015
+ }
3016
+ // =========================================================================
3017
+ // DOM update helpers
3018
+ // =========================================================================
3019
+ updateDisabledState() {
3020
+ if (!this._buttonEl) return;
3021
+ const e = this.disabled, t = this.discoverable, i = this.loading, s = e && !t, a = e || i;
3022
+ s ? this._buttonEl.setAttribute("disabled", "") : this._buttonEl.removeAttribute("disabled"), a ? this._buttonEl.setAttribute("aria-disabled", "true") : this._buttonEl.removeAttribute("aria-disabled");
3023
+ }
3024
+ updateLoadingState() {
3025
+ if (!this._buttonEl) return;
3026
+ if (this.loading) {
3027
+ if (this._buttonEl.setAttribute("aria-busy", "true"), this._buttonEl.setAttribute("aria-disabled", "true"), !this._buttonEl.querySelector(".button-spinner")) {
3028
+ const t = document.createElement("span");
3029
+ t.className = "button-spinner", t.setAttribute("aria-hidden", "true"), t.setAttribute("part", "spinner"), this._buttonEl.insertBefore(t, this._buttonEl.firstChild);
3030
+ }
3031
+ } else {
3032
+ this._buttonEl.removeAttribute("aria-busy");
3033
+ const t = this._buttonEl.querySelector(".button-spinner");
3034
+ t == null || t.remove(), this.updateDisabledState();
758
3035
  }
759
3036
  }
760
- selectItem(t) {
761
- const e = this._menuItems[t];
762
- e && (this.emit("a11y-menu-select", { item: e, index: t }), e.click()), this.close();
3037
+ // =========================================================================
3038
+ // Public methods
3039
+ // =========================================================================
3040
+ /** Focus the button element */
3041
+ focus() {
3042
+ var e;
3043
+ (e = this._buttonEl) == null || e.focus();
3044
+ }
3045
+ /** Blur the button element */
3046
+ blur() {
3047
+ var e;
3048
+ (e = this._buttonEl) == null || e.blur();
3049
+ }
3050
+ /** Programmatically click the button */
3051
+ click() {
3052
+ var e;
3053
+ (e = this._buttonEl) == null || e.click();
3054
+ }
3055
+ }
3056
+ u("a11y-button", G);
3057
+ class X extends c {
3058
+ constructor() {
3059
+ super(...arguments), this._label = "", this._disabled = !1;
3060
+ }
3061
+ static get observedAttributes() {
3062
+ return ["label", "disabled"];
3063
+ }
3064
+ get label() {
3065
+ return this._label;
3066
+ }
3067
+ set label(e) {
3068
+ this._label = e, this.setAttribute("label", e), this.updateLabel();
3069
+ }
3070
+ get disabled() {
3071
+ return this._disabled;
3072
+ }
3073
+ set disabled(e) {
3074
+ const t = !!e;
3075
+ this._disabled !== t && (this._disabled = t, t ? (this.setAttribute("disabled", ""), this.setAttribute("aria-disabled", "true")) : (this.removeAttribute("disabled"), this.removeAttribute("aria-disabled")));
3076
+ }
3077
+ setupAccessibility() {
3078
+ this.setAttribute("role", "group"), this._label = this.getAttribute("label") || "", this._disabled = this.hasAttribute("disabled"), this._disabled && this.setAttribute("aria-disabled", "true");
763
3079
  }
764
- updateMenuVisibility() {
765
- var i;
766
- const t = (i = this.shadowRoot) == null ? void 0 : i.querySelector(".menu-content"), e = this.querySelector('[slot="trigger"]');
767
- this._open ? (t == null || t.removeAttribute("hidden"), e == null || e.setAttribute("aria-expanded", "true"), this.updateMenuItems(), this.emit("a11y-menu-open")) : (t == null || t.setAttribute("hidden", ""), e == null || e.setAttribute("aria-expanded", "false"), this._highlightedIndex = -1, this._menuItems.forEach((s) => {
768
- s.removeAttribute("data-highlighted");
769
- }), e == null || e.focus(), this.emit("a11y-menu-close"));
3080
+ render() {
3081
+ this.shadowRoot || this.attachShadow({ mode: "open" });
3082
+ const e = `${this._id}-label`;
3083
+ this.shadowRoot.innerHTML = `
3084
+ <style>${Se}</style>
3085
+ <div class="optgroup-wrapper" part="group">
3086
+ <div class="optgroup-label" part="label" id="${e}" role="presentation">
3087
+ ${this._label}
3088
+ </div>
3089
+ <div class="optgroup-options" part="options" role="none">
3090
+ <slot></slot>
3091
+ </div>
3092
+ </div>
3093
+ `, this.setAttribute("aria-labelledby", e);
770
3094
  }
771
- /**
772
- * Show the menu
773
- */
774
- show() {
775
- this.open = !0;
3095
+ setupEventListeners() {
776
3096
  }
777
- /**
778
- * Hide the menu
779
- */
780
- close() {
781
- this.open = !1;
3097
+ cleanupEventListeners() {
782
3098
  }
783
- /**
784
- * Toggle the menu
785
- */
786
- toggle() {
787
- this.open = !this._open;
3099
+ updateLabel() {
3100
+ var t;
3101
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector(".optgroup-label");
3102
+ e && (e.textContent = this._label);
3103
+ }
3104
+ attributeChangedCallback(e, t, i) {
3105
+ if (t !== i)
3106
+ switch (e) {
3107
+ case "label":
3108
+ this._label = i || "", this.updateLabel();
3109
+ break;
3110
+ case "disabled":
3111
+ this._disabled = i !== null, this._disabled ? this.setAttribute("aria-disabled", "true") : this.removeAttribute("aria-disabled");
3112
+ break;
3113
+ }
788
3114
  }
789
3115
  }
790
- d("a11y-menu", _);
791
- class x extends h {
3116
+ class V extends c {
792
3117
  constructor() {
793
- super(...arguments), this._tabs = [], this._panels = [], this._selectedIndex = 0, this.updateTabsAndPanels = () => {
794
- this._tabs = Array.from(
795
- this.querySelectorAll('[role="tab"]')
796
- ), this._panels = Array.from(
797
- this.querySelectorAll('[role="tabpanel"]')
798
- ), this._tabs.forEach((t, e) => {
799
- const i = this._panels[e], s = t.id || `${this._id}-tab-${e}`, o = (i == null ? void 0 : i.id) || `${this._id}-panel-${e}`;
800
- t.id = s, t.setAttribute("aria-controls", o), t.setAttribute("tabindex", e === this._selectedIndex ? "0" : "-1"), t.setAttribute("aria-selected", String(e === this._selectedIndex)), t.hasAttribute("slot") || t.setAttribute("slot", "tab"), i && (i.id = o, i.setAttribute("aria-labelledby", s), i.setAttribute("tabindex", "0"), i.hidden = e !== this._selectedIndex, i.hasAttribute("slot") || i.setAttribute("slot", "panel"));
801
- }), this.updateSelection();
802
- }, this.handleClick = (t) => {
803
- const e = t.target;
804
- if (e.getAttribute("role") === "tab") {
805
- const i = this._tabs.indexOf(e);
806
- i !== -1 && e.getAttribute("aria-disabled") !== "true" && this.selectTab(i);
807
- }
808
- }, this.handleKeyDown = (t) => {
809
- var l;
810
- if (t.target.getAttribute("role") !== "tab") return;
811
- const i = this.orientation === "horizontal", s = i ? "ArrowRight" : "ArrowDown", o = i ? "ArrowLeft" : "ArrowUp";
812
- let a = this._selectedIndex;
813
- switch (t.key) {
814
- case s:
815
- t.preventDefault(), a = (this._selectedIndex + 1) % this._tabs.length;
816
- break;
817
- case o:
818
- t.preventDefault(), a = (this._selectedIndex - 1 + this._tabs.length) % this._tabs.length;
819
- break;
820
- case "Home":
821
- t.preventDefault(), a = 0;
822
- break;
823
- case "End":
824
- t.preventDefault(), a = this._tabs.length - 1;
825
- break;
826
- default:
827
- return;
3118
+ super(...arguments), this._value = "", this._disabled = !1, this._selected = !1, this._discoverable = !0, this.handleClick = (e) => {
3119
+ if (this.effectivelyDisabled) {
3120
+ e.preventDefault();
3121
+ return;
828
3122
  }
829
- (l = this._tabs[a]) == null || l.focus(), this.activationMode === "automatic" && this.selectTab(a);
3123
+ this.dispatchEvent(
3124
+ new CustomEvent("option-select", {
3125
+ detail: { value: this._value },
3126
+ bubbles: !0,
3127
+ composed: !0
3128
+ })
3129
+ );
830
3130
  };
831
3131
  }
832
3132
  static get observedAttributes() {
833
- return ["orientation", "activation-mode", "selected-index"];
834
- }
835
- get selectedIndex() {
836
- return this._selectedIndex;
3133
+ return ["value", "disabled", "discoverable"];
837
3134
  }
838
- set selectedIndex(t) {
839
- t >= 0 && t < this._tabs.length && (this._selectedIndex = t, this.updateSelection());
3135
+ get value() {
3136
+ return this._value;
840
3137
  }
841
- get orientation() {
842
- return this.getAttribute("orientation") || "horizontal";
3138
+ set value(e) {
3139
+ this._value = e, this.setAttribute("value", e);
843
3140
  }
844
- get activationMode() {
845
- return this.getAttribute("activation-mode") || "automatic";
3141
+ get disabled() {
3142
+ return this._disabled;
846
3143
  }
847
- setupAccessibility() {
848
- this.updateTabsAndPanels();
3144
+ set disabled(e) {
3145
+ const t = !!e;
3146
+ this._disabled !== t && (this._disabled = t, t ? (this.setAttribute("disabled", ""), this.setAttribute("aria-disabled", "true")) : (this.removeAttribute("disabled"), this.removeAttribute("aria-disabled")));
849
3147
  }
850
- render() {
851
- const t = this.attachShadow({ mode: "open" });
852
- t.innerHTML = `
853
- <style>${P}</style>
854
- <div class="tablist" role="tablist" aria-orientation="${this.orientation}" part="tablist">
855
- <slot name="tab"></slot>
856
- </div>
857
- <div class="panels" part="panels">
858
- <slot name="panel"></slot>
859
- </div>
860
- <slot></slot>
861
- `;
3148
+ get selected() {
3149
+ return this._selected;
862
3150
  }
863
- setupEventListeners() {
864
- var s, o, a;
865
- this.addEventListener("click", this.handleClick), this.addEventListener("keydown", this.handleKeyDown);
866
- const t = (s = this.shadowRoot) == null ? void 0 : s.querySelector('slot[name="tab"]'), e = (o = this.shadowRoot) == null ? void 0 : o.querySelector('slot[name="panel"]'), i = (a = this.shadowRoot) == null ? void 0 : a.querySelector("slot:not([name])");
867
- t == null || t.addEventListener("slotchange", this.updateTabsAndPanels), e == null || e.addEventListener("slotchange", this.updateTabsAndPanels), i == null || i.addEventListener("slotchange", this.updateTabsAndPanels);
3151
+ set selected(e) {
3152
+ const t = !!e;
3153
+ this._selected !== t && (this._selected = t, this.setAttribute("aria-selected", String(t)));
868
3154
  }
869
- onAttributeChange(t, e, i) {
870
- var s;
871
- if (t === "orientation") {
872
- const o = (s = this.shadowRoot) == null ? void 0 : s.querySelector('[role="tablist"]');
873
- o == null || o.setAttribute("aria-orientation", i || "horizontal");
874
- }
875
- t === "selected-index" && i && (this.selectedIndex = parseInt(i, 10));
876
- }
877
- selectTab(t) {
878
- const e = this._selectedIndex;
879
- if (this._selectedIndex = t, this.updateSelection(), e !== t) {
880
- const i = this._tabs[t];
881
- r(`${(i == null ? void 0 : i.textContent) || "Tab"} selected`), this.emit("a11y-tabs-change", {
882
- index: t,
883
- tab: this._tabs[t],
884
- panel: this._panels[t]
885
- });
886
- }
3155
+ get discoverable() {
3156
+ return this._discoverable;
887
3157
  }
888
- updateSelection() {
889
- this._tabs.forEach((t, e) => {
890
- const i = e === this._selectedIndex;
891
- t.setAttribute("aria-selected", String(i)), t.setAttribute("tabindex", i ? "0" : "-1");
892
- }), this._panels.forEach((t, e) => {
893
- t.hidden = e !== this._selectedIndex;
894
- });
3158
+ set discoverable(e) {
3159
+ this._discoverable = !!e;
895
3160
  }
896
3161
  /**
897
- * Select a tab by index
3162
+ * Whether this option is effectively disabled (own disabled or group disabled)
898
3163
  */
899
- select(t) {
900
- this.selectTab(t);
3164
+ get effectivelyDisabled() {
3165
+ if (this._disabled) return !0;
3166
+ const e = this.closest("a11y-optgroup");
3167
+ return (e == null ? void 0 : e.disabled) ?? !1;
901
3168
  }
902
- /**
903
- * Select next tab
904
- */
905
- next() {
906
- this.selectTab((this._selectedIndex + 1) % this._tabs.length);
3169
+ setupAccessibility() {
3170
+ this.setAttribute("role", "option"), this.setAttribute("aria-selected", "false"), this._value = this.getAttribute("value") || "", this._disabled = this.hasAttribute("disabled"), this._disabled && this.setAttribute("aria-disabled", "true");
3171
+ const e = this.getAttribute("discoverable");
3172
+ (e === "false" || e === "0") && (this._discoverable = !1);
907
3173
  }
908
- /**
909
- * Select previous tab
910
- */
911
- previous() {
912
- this.selectTab(
913
- (this._selectedIndex - 1 + this._tabs.length) % this._tabs.length
914
- );
3174
+ render() {
3175
+ this.shadowRoot || this.attachShadow({ mode: "open" }), this.shadowRoot.innerHTML = `
3176
+ <style>${Le}</style>
3177
+ <div class="option-wrapper" part="option">
3178
+ <span class="option-content" part="content"><slot></slot></span>
3179
+ <span class="check-mark" part="check" aria-hidden="true">&#10003;</span>
3180
+ </div>
3181
+ `;
915
3182
  }
916
- }
917
- d("a11y-tabs", x);
918
- class v extends h {
919
- constructor() {
920
- super(...arguments), this._open = !1, this._highlightedIndex = -1, this._options = [], this._filteredOptions = [], this._inputValue = "", this._selectedValue = null, this._inputElement = null, this._listboxElement = null, this.updateOptions = () => {
921
- const t = Array.from(this.querySelectorAll("option"));
922
- this._options = t.map((e) => ({
923
- value: e.getAttribute("value") || e.textContent || "",
924
- label: e.textContent || "",
925
- disabled: e.hasAttribute("disabled"),
926
- element: e
927
- })), this._filteredOptions = [...this._options], this.renderOptions();
928
- }, this.handleInput = (t) => {
929
- const e = t.target;
930
- this._inputValue = e.value;
931
- const i = this._inputValue.toLowerCase();
932
- this._filteredOptions = i ? this._options.filter((o) => o.label.toLowerCase().includes(i)) : [...this._options], this.renderOptions(), this.open = !0, this._highlightedIndex = 0, this.updateHighlight(), this.updateClearButton();
933
- const s = this._filteredOptions.length;
934
- r(
935
- s === 0 ? "No results" : `${s} result${s === 1 ? "" : "s"} available`
936
- );
937
- }, this.handleFocus = () => {
938
- this.open = !0;
939
- }, this.handleBlur = () => {
940
- setTimeout(() => {
941
- var t;
942
- (t = this.shadowRoot) != null && t.activeElement || (this.open = !1);
943
- }, 150);
944
- }, this.handleKeyDown = (t) => {
945
- switch (t.key) {
946
- case "ArrowDown":
947
- t.preventDefault(), this._open ? this._highlightedIndex = Math.min(
948
- this._highlightedIndex + 1,
949
- this._filteredOptions.length - 1
950
- ) : (this.open = !0, this._highlightedIndex = 0), this.updateHighlight();
951
- break;
952
- case "ArrowUp":
953
- t.preventDefault(), this._open ? this._highlightedIndex = Math.max(this._highlightedIndex - 1, 0) : (this.open = !0, this._highlightedIndex = this._filteredOptions.length - 1), this.updateHighlight();
954
- break;
955
- case "Enter":
956
- if (t.preventDefault(), this._open && this._highlightedIndex >= 0) {
957
- const e = this._filteredOptions[this._highlightedIndex];
958
- e && !e.disabled && this.selectOption(e);
959
- }
960
- break;
961
- case "Escape":
962
- t.preventDefault(), this.open = !1, this._highlightedIndex = -1;
963
- break;
964
- case "Home":
965
- this._open && (t.preventDefault(), this._highlightedIndex = 0, this.updateHighlight());
3183
+ setupEventListeners() {
3184
+ this.addEventListener("click", this.handleClick);
3185
+ }
3186
+ cleanupEventListeners() {
3187
+ this.removeEventListener("click", this.handleClick);
3188
+ }
3189
+ attributeChangedCallback(e, t, i) {
3190
+ if (t !== i)
3191
+ switch (e) {
3192
+ case "value":
3193
+ this._value = i || "";
966
3194
  break;
967
- case "End":
968
- this._open && (t.preventDefault(), this._highlightedIndex = this._filteredOptions.length - 1, this.updateHighlight());
3195
+ case "disabled":
3196
+ this._disabled = i !== null, this._disabled ? this.setAttribute("aria-disabled", "true") : this.removeAttribute("aria-disabled");
969
3197
  break;
970
- case "Tab":
971
- this._open && (this.open = !1, this._highlightedIndex = -1);
3198
+ case "discoverable":
3199
+ i === null ? this._discoverable = !0 : i === "false" || i === "0" ? this._discoverable = !1 : this._discoverable = !0;
972
3200
  break;
973
3201
  }
974
- }, this.handleOptionClick = (t) => {
975
- const e = t.currentTarget, i = parseInt(e.dataset.index || "0", 10), s = this._filteredOptions[i];
976
- s && !s.disabled && this.selectOption(s);
977
- }, this.handleOptionHover = (t) => {
978
- const e = t.currentTarget, i = parseInt(e.dataset.index || "0", 10), s = this._filteredOptions[i];
979
- s && !s.disabled && (this._highlightedIndex = i, this.updateHighlight());
980
- }, this.handleClear = () => {
981
- this._inputValue = "", this._selectedValue = null, this._inputElement && (this._inputElement.value = "", this._inputElement.focus()), this._filteredOptions = [...this._options], this.renderOptions(), this.updateClearButton(), this.emit("a11y-combobox-clear"), this.emit("a11y-combobox-change", { value: null, label: null });
982
- }, this.handleOutsideClick = (t) => {
983
- if (!this._open) return;
984
- t.composedPath().includes(this) || (this.open = !1);
3202
+ }
3203
+ }
3204
+ class W extends c {
3205
+ constructor() {
3206
+ super(...arguments), this._value = null, this._values = /* @__PURE__ */ new Set(), this._multiple = !1, this._disabled = !1, this._discoverable = !0, this._orientation = "vertical", this._focusedIndex = -1, this._typeAhead = null, this.handleFocus = () => {
3207
+ if (this._focusedIndex >= 0) return;
3208
+ const e = this.getAllOptions();
3209
+ if (!this._multiple && this._value) {
3210
+ const t = e.findIndex((i) => i.value === this._value);
3211
+ if (t >= 0) {
3212
+ this._focusedIndex = t, this.updateFocusHighlight();
3213
+ return;
3214
+ }
3215
+ } else if (this._multiple && this._values.size > 0) {
3216
+ const t = e.findIndex((i) => this._values.has(i.value));
3217
+ if (t >= 0) {
3218
+ this._focusedIndex = t, this.updateFocusHighlight();
3219
+ return;
3220
+ }
3221
+ }
3222
+ this._focusedIndex = this.findFirstEnabled(), this.updateFocusHighlight();
3223
+ }, this.handleOptionSelect = (e) => {
3224
+ var r;
3225
+ if (this._disabled) return;
3226
+ const t = (r = e.detail) == null ? void 0 : r.value;
3227
+ if (t === void 0) return;
3228
+ const i = this.getAllOptions(), s = i.find((l) => l.value === t);
3229
+ if (!s) return;
3230
+ const a = i.indexOf(s);
3231
+ this._focusedIndex = a, this.updateFocusHighlight(), this.selectOption(s), this.focus();
3232
+ }, this.handleKeyDown = (e) => {
3233
+ var a, r, l;
3234
+ if (this._disabled && !this._discoverable) return;
3235
+ const t = this.getAllOptions();
3236
+ if (t.length === 0) return;
3237
+ let i = null, s = !1;
3238
+ if (this._multiple)
3239
+ switch (e.key) {
3240
+ case "ArrowDown":
3241
+ e.shiftKey ? (i = this.findNextEnabled(this._focusedIndex, 1), i >= 0 && this.toggleOptionSelection(t[i])) : i = this.findNextEnabled(this._focusedIndex, 1), s = !0;
3242
+ break;
3243
+ case "ArrowUp":
3244
+ e.shiftKey ? (i = this.findNextEnabled(this._focusedIndex, -1), i >= 0 && this.toggleOptionSelection(t[i])) : i = this.findNextEnabled(this._focusedIndex, -1), s = !0;
3245
+ break;
3246
+ case " ":
3247
+ this._focusedIndex >= 0 && t[this._focusedIndex] != null && this.toggleOptionSelection(t[this._focusedIndex]), s = !0;
3248
+ break;
3249
+ case "Home":
3250
+ e.ctrlKey && e.shiftKey ? (this.selectRange(this.findFirstEnabled(), this._focusedIndex), i = this.findFirstEnabled()) : i = this.findFirstEnabled(), s = !0;
3251
+ break;
3252
+ case "End":
3253
+ e.ctrlKey && e.shiftKey ? (this.selectRange(this._focusedIndex, this.findLastEnabled()), i = this.findLastEnabled()) : i = this.findLastEnabled(), s = !0;
3254
+ break;
3255
+ case "a":
3256
+ (e.ctrlKey || e.metaKey) && (this.toggleSelectAll(), s = !0);
3257
+ break;
3258
+ default:
3259
+ if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
3260
+ const o = (a = this._typeAhead) == null ? void 0 : a.type(e.key);
3261
+ if (o) {
3262
+ const d = t.findIndex(
3263
+ (h) => {
3264
+ var g;
3265
+ return (((g = h.textContent) == null ? void 0 : g.trim()) || "") === o && !h.effectivelyDisabled;
3266
+ }
3267
+ );
3268
+ d >= 0 && (i = d, s = !0);
3269
+ }
3270
+ }
3271
+ break;
3272
+ }
3273
+ else
3274
+ switch (e.key) {
3275
+ case "ArrowDown":
3276
+ i = this.findNextEnabled(this._focusedIndex, 1), s = !0;
3277
+ break;
3278
+ case "ArrowUp":
3279
+ i = this.findNextEnabled(this._focusedIndex, -1), s = !0;
3280
+ break;
3281
+ case "Home":
3282
+ i = this.findFirstEnabled(), s = !0;
3283
+ break;
3284
+ case "End":
3285
+ i = this.findLastEnabled(), s = !0;
3286
+ break;
3287
+ default:
3288
+ if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
3289
+ const o = (r = this._typeAhead) == null ? void 0 : r.type(e.key);
3290
+ if (o) {
3291
+ const d = t.findIndex(
3292
+ (h) => {
3293
+ var g;
3294
+ return (((g = h.textContent) == null ? void 0 : g.trim()) || "") === o && !h.effectivelyDisabled;
3295
+ }
3296
+ );
3297
+ d >= 0 && (i = d, s = !0);
3298
+ }
3299
+ }
3300
+ break;
3301
+ }
3302
+ if (s && (e.preventDefault(), e.stopPropagation()), i !== null && i >= 0) {
3303
+ this._focusedIndex = i, this.updateFocusHighlight();
3304
+ const o = t[i];
3305
+ if (!this._multiple && o)
3306
+ this.selectSingle(o);
3307
+ else if (o) {
3308
+ const d = ((l = o.textContent) == null ? void 0 : l.trim()) || o.value, h = this._values.has(o.value);
3309
+ p(`${d}${h ? ", selected" : ""}`);
3310
+ }
3311
+ }
985
3312
  };
986
3313
  }
987
3314
  static get observedAttributes() {
988
- return ["open", "value", "placeholder", "disabled", "clearable"];
3315
+ return [
3316
+ "value",
3317
+ "multiple",
3318
+ "disabled",
3319
+ "discoverable",
3320
+ "orientation",
3321
+ "aria-label",
3322
+ "aria-labelledby"
3323
+ ];
3324
+ }
3325
+ // ===== Getters/Setters =====
3326
+ get value() {
3327
+ return this._multiple ? Array.from(this._values) : this._value || "";
3328
+ }
3329
+ set value(e) {
3330
+ if (this._multiple) {
3331
+ const t = Array.isArray(e) ? e : String(e).split(",").filter(Boolean);
3332
+ this._values = new Set(t), this.setAttribute("value", t.join(","));
3333
+ } else {
3334
+ const t = Array.isArray(e) ? e[0] || "" : String(e);
3335
+ this._value = t, this.setAttribute("value", t);
3336
+ }
3337
+ this.syncOptionStates();
989
3338
  }
990
- get open() {
991
- return this._open;
3339
+ get multiple() {
3340
+ return this._multiple;
992
3341
  }
993
- set open(t) {
994
- const e = this._open;
995
- this._open = t, t !== e && this.updateListboxVisibility(), this.toggleAttribute("open", t);
3342
+ set multiple(e) {
3343
+ const t = !!e;
3344
+ this._multiple !== t && (this._multiple = t, t ? (this.setAttribute("multiple", ""), this.setAttribute("aria-multiselectable", "true")) : (this.removeAttribute("multiple"), this.removeAttribute("aria-multiselectable")));
996
3345
  }
997
- get value() {
998
- return this._selectedValue;
3346
+ get disabled() {
3347
+ return this._disabled;
3348
+ }
3349
+ set disabled(e) {
3350
+ const t = !!e;
3351
+ this._disabled !== t && (this._disabled = t, t ? (this.setAttribute("disabled", ""), this.setAttribute("aria-disabled", "true")) : (this.removeAttribute("disabled"), this.removeAttribute("aria-disabled")));
3352
+ }
3353
+ get discoverable() {
3354
+ return this._discoverable;
3355
+ }
3356
+ set discoverable(e) {
3357
+ this._discoverable = !!e;
999
3358
  }
1000
- set value(t) {
1001
- this._selectedValue = t;
1002
- const e = this._options.find((i) => i.value === t);
1003
- e && (this._inputValue = e.label, this._inputElement && (this._inputElement.value = e.label)), this.setAttribute("value", t || "");
3359
+ get orientation() {
3360
+ return this._orientation;
3361
+ }
3362
+ set orientation(e) {
3363
+ this._orientation = e, this.setAttribute("orientation", e), this.setAttribute("aria-orientation", e);
1004
3364
  }
3365
+ // ===== Lifecycle =====
1005
3366
  setupAccessibility() {
3367
+ this.setAttribute("role", "listbox"), this.setAttribute("aria-orientation", this._orientation), !(this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby")) && process.env.NODE_ENV !== "production" && console.warn(
3368
+ "[Compa11y Listbox]: Listbox has no accessible label. Use aria-label or aria-labelledby."
3369
+ ), this._multiple = this.hasAttribute("multiple"), this._multiple && this.setAttribute("aria-multiselectable", "true"), this._disabled = this.hasAttribute("disabled"), this._disabled && this.setAttribute("aria-disabled", "true");
3370
+ const t = this.getAttribute("orientation");
3371
+ (t === "horizontal" || t === "vertical") && (this._orientation = t);
3372
+ const i = this.getAttribute("discoverable");
3373
+ (i === "false" || i === "0") && (this._discoverable = !1);
3374
+ const s = this.getAttribute("value");
3375
+ s && (this._multiple ? this._values = new Set(s.split(",").filter(Boolean)) : this._value = s), this._disabled && !this._discoverable ? this.setAttribute("tabindex", "-1") : this.setAttribute("tabindex", "0");
1006
3376
  }
1007
3377
  render() {
1008
- const t = this.attachShadow({ mode: "open" }), e = `${this._id}-input`, i = `${this._id}-listbox`, s = this.getAttribute("placeholder") || "Search...", o = this.hasAttribute("clearable");
1009
- t.innerHTML = `
1010
- <style>${N}</style>
1011
- <div class="combobox-wrapper" part="wrapper">
1012
- <div class="input-wrapper" part="input-wrapper">
1013
- <input
1014
- id="${e}"
1015
- type="text"
1016
- role="combobox"
1017
- autocomplete="off"
1018
- aria-expanded="false"
1019
- aria-controls="${i}"
1020
- aria-haspopup="listbox"
1021
- aria-autocomplete="list"
1022
- placeholder="${s}"
1023
- part="input"
1024
- />
1025
- ${o ? `
1026
- <button
1027
- type="button"
1028
- class="clear-button"
1029
- aria-label="Clear selection"
1030
- tabindex="-1"
1031
- hidden
1032
- part="clear-button"
1033
- >×</button>
1034
- ` : ""}
1035
- <span class="chevron" aria-hidden="true" part="chevron">▼</span>
1036
- </div>
1037
- <ul
1038
- id="${i}"
1039
- role="listbox"
1040
- aria-labelledby="${e}"
1041
- class="listbox"
1042
- tabindex="-1"
1043
- hidden
1044
- part="listbox"
1045
- ></ul>
1046
- </div>
1047
- <div class="options-source" hidden>
3378
+ this.shadowRoot || this.attachShadow({ mode: "open" }), this.shadowRoot.innerHTML = `
3379
+ <style>${$e}</style>
3380
+ <div class="listbox-wrapper" part="wrapper">
1048
3381
  <slot></slot>
1049
3382
  </div>
1050
- `, this._inputElement = t.querySelector("input"), this._listboxElement = t.querySelector(".listbox");
3383
+ `;
1051
3384
  }
1052
3385
  setupEventListeners() {
1053
- var i, s, o, a, l, u;
1054
- (i = this._inputElement) == null || i.addEventListener("input", this.handleInput), (s = this._inputElement) == null || s.addEventListener("focus", this.handleFocus), (o = this._inputElement) == null || o.addEventListener("blur", this.handleBlur), (a = this._inputElement) == null || a.addEventListener("keydown", this.handleKeyDown);
1055
- const t = (l = this.shadowRoot) == null ? void 0 : l.querySelector(".clear-button");
1056
- t == null || t.addEventListener("click", this.handleClear), document.addEventListener("mousedown", this.handleOutsideClick);
1057
- const e = (u = this.shadowRoot) == null ? void 0 : u.querySelector("slot");
1058
- e == null || e.addEventListener("slotchange", this.updateOptions), this.updateOptions();
3386
+ var t;
3387
+ this.addEventListener("keydown", this.handleKeyDown), this.addEventListener("focus", this.handleFocus), this.addEventListener("option-select", this.handleOptionSelect);
3388
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector("slot");
3389
+ e && e.addEventListener("slotchange", () => {
3390
+ this.rebuildTypeAhead(), this.syncOptionStates();
3391
+ }), this.rebuildTypeAhead(), this.syncOptionStates();
1059
3392
  }
1060
3393
  cleanupEventListeners() {
1061
- document.removeEventListener("mousedown", this.handleOutsideClick);
1062
- }
1063
- onAttributeChange(t, e, i) {
1064
- t === "open" && (this.open = i !== null), t === "value" && (this.value = i), t === "disabled" && this._inputElement && (this._inputElement.disabled = i !== null), t === "placeholder" && this._inputElement && (this._inputElement.placeholder = i || "Search...");
1065
- }
1066
- renderOptions() {
1067
- this._listboxElement && (this._listboxElement.innerHTML = this._filteredOptions.length === 0 ? '<li role="presentation" class="empty-message" part="empty">No results found</li>' : this._filteredOptions.map(
1068
- (t, e) => `
1069
- <li
1070
- id="${this._id}-option-${e}"
1071
- role="option"
1072
- aria-selected="${this._selectedValue === t.value}"
1073
- aria-disabled="${t.disabled}"
1074
- data-value="${t.value}"
1075
- data-index="${e}"
1076
- part="option"
1077
- ${t.disabled ? 'class="disabled"' : ""}
1078
- >${t.label}</li>
1079
- `
1080
- ).join(""), this._listboxElement.querySelectorAll('[role="option"]').forEach((t) => {
1081
- t.addEventListener("click", this.handleOptionClick), t.addEventListener("mouseenter", this.handleOptionHover);
1082
- }));
1083
- }
1084
- selectOption(t) {
1085
- this._selectedValue = t.value, this._inputValue = t.label, this._inputElement && (this._inputElement.value = t.label), this.open = !1, this._highlightedIndex = -1, this.renderOptions(), this.updateClearButton(), r(`${t.label} selected`), this.emit("a11y-combobox-select", {
1086
- value: t.value,
1087
- label: t.label
1088
- }), this.emit("a11y-combobox-change", {
1089
- value: t.value,
1090
- label: t.label
1091
- });
1092
- }
1093
- updateHighlight() {
1094
- var t, e, i, s;
1095
- if ((t = this._listboxElement) == null || t.querySelectorAll('[role="option"]').forEach((o, a) => {
1096
- o.classList.toggle("highlighted", a === this._highlightedIndex);
1097
- }), this._highlightedIndex >= 0) {
1098
- const o = `${this._id}-option-${this._highlightedIndex}`;
1099
- (e = this._inputElement) == null || e.setAttribute("aria-activedescendant", o);
1100
- const a = (i = this._listboxElement) == null ? void 0 : i.querySelector(`#${o}`);
1101
- a == null || a.scrollIntoView({ block: "nearest", behavior: "smooth" });
1102
- } else
1103
- (s = this._inputElement) == null || s.removeAttribute("aria-activedescendant");
1104
- }
1105
- updateListboxVisibility() {
1106
- !this._listboxElement || !this._inputElement || (this._open ? (this._listboxElement.hidden = !1, this._inputElement.setAttribute("aria-expanded", "true"), this.updateListboxPosition(), this.emit("a11y-combobox-open")) : (this._listboxElement.hidden = !0, this._inputElement.setAttribute("aria-expanded", "false"), this._highlightedIndex = -1, this.updateHighlight(), this._listboxElement.style.top = "", this._listboxElement.style.bottom = "", this.removeAttribute("data-position"), this.emit("a11y-combobox-close")));
3394
+ this.removeEventListener("keydown", this.handleKeyDown), this.removeEventListener("focus", this.handleFocus), this.removeEventListener("option-select", this.handleOptionSelect);
1107
3395
  }
1108
- updateListboxPosition() {
1109
- if (!this._listboxElement || !this._inputElement) return;
1110
- const t = this._inputElement.getBoundingClientRect(), e = window.innerHeight, i = Math.min(
1111
- this._listboxElement.scrollHeight,
1112
- 200
1113
- // max-height from CSS
1114
- ), s = e - t.bottom, o = t.top;
1115
- s < i + 8 && o > s ? (this._listboxElement.style.top = "auto", this._listboxElement.style.bottom = "100%", this._listboxElement.style.marginTop = "0", this._listboxElement.style.marginBottom = "4px", this.setAttribute("data-position", "top")) : (this._listboxElement.style.top = "100%", this._listboxElement.style.bottom = "auto", this._listboxElement.style.marginTop = "4px", this._listboxElement.style.marginBottom = "0", this.setAttribute("data-position", "bottom"));
3396
+ // ===== Option Queries =====
3397
+ getAllOptions() {
3398
+ return Array.from(this.querySelectorAll("a11y-option"));
1116
3399
  }
1117
- updateClearButton() {
1118
- var e;
1119
- const t = (e = this.shadowRoot) == null ? void 0 : e.querySelector(
1120
- ".clear-button"
1121
- );
1122
- t && (t.hidden = !this._inputValue);
3400
+ getEnabledOptions() {
3401
+ return this.getAllOptions().filter((e) => !e.effectivelyDisabled);
1123
3402
  }
1124
- /**
1125
- * Programmatic open
1126
- */
1127
- show() {
1128
- this.open = !0;
3403
+ getEnabledIndices() {
3404
+ const e = this.getAllOptions(), t = [];
3405
+ return e.forEach((i, s) => {
3406
+ i.effectivelyDisabled || t.push(s);
3407
+ }), t;
1129
3408
  }
1130
- /**
1131
- * Programmatic close
1132
- */
1133
- close() {
1134
- this.open = !1;
3409
+ // ===== State Sync =====
3410
+ syncOptionStates() {
3411
+ this.getAllOptions().forEach((t) => {
3412
+ this._multiple ? t.selected = this._values.has(t.value) : t.selected = t.value === this._value;
3413
+ });
1135
3414
  }
1136
- /**
1137
- * Clear the selection
1138
- */
1139
- clear() {
1140
- this.handleClear();
3415
+ updateFocusHighlight() {
3416
+ const e = this.getAllOptions();
3417
+ e.forEach((i, s) => {
3418
+ s === this._focusedIndex ? i.toggleAttribute("data-focused", !0) : i.removeAttribute("data-focused");
3419
+ });
3420
+ const t = this._focusedIndex >= 0 ? e[this._focusedIndex] : void 0;
3421
+ t ? (this.setAttribute("aria-activedescendant", t.id), t.scrollIntoView({ block: "nearest" })) : this.removeAttribute("aria-activedescendant");
3422
+ }
3423
+ // ===== Navigation Helpers =====
3424
+ findNextEnabled(e, t) {
3425
+ const i = this.getEnabledIndices();
3426
+ if (i.length === 0) return -1;
3427
+ const s = i.indexOf(e);
3428
+ if (s === -1)
3429
+ return t === 1 ? i[0] : i[i.length - 1];
3430
+ const a = s + t;
3431
+ return a < 0 || a >= i.length ? -1 : i[a];
3432
+ }
3433
+ findFirstEnabled() {
3434
+ const e = this.getEnabledIndices();
3435
+ return e.length > 0 ? e[0] : -1;
3436
+ }
3437
+ findLastEnabled() {
3438
+ const e = this.getEnabledIndices();
3439
+ return e.length > 0 ? e[e.length - 1] : -1;
3440
+ }
3441
+ // ===== Selection =====
3442
+ selectOption(e) {
3443
+ e.effectivelyDisabled || this._disabled || (this._multiple ? this.toggleOptionSelection(e) : this.selectSingle(e));
3444
+ }
3445
+ selectSingle(e) {
3446
+ var i;
3447
+ const t = this._value;
3448
+ if (this._value = e.value, this.setAttribute("value", e.value), this.syncOptionStates(), t !== this._value) {
3449
+ const s = ((i = e.textContent) == null ? void 0 : i.trim()) || e.value;
3450
+ this.emit("change", { value: this._value, label: s }), this.emit("a11y-listbox-change", { value: this._value, label: s }), p(`${s} selected`);
3451
+ }
3452
+ }
3453
+ toggleOptionSelection(e) {
3454
+ var s;
3455
+ if (e.effectivelyDisabled || this._disabled) return;
3456
+ const t = ((s = e.textContent) == null ? void 0 : s.trim()) || e.value;
3457
+ this._values.has(e.value) ? (this._values.delete(e.value), e.selected = !1, p(`${t} deselected`)) : (this._values.add(e.value), e.selected = !0, p(`${t} selected`));
3458
+ const i = Array.from(this._values);
3459
+ this.setAttribute("value", i.join(",")), this.emit("change", { value: i }), this.emit("a11y-listbox-change", { value: i });
3460
+ }
3461
+ selectRange(e, t) {
3462
+ const i = this.getAllOptions(), s = Math.min(e, t), a = Math.max(e, t);
3463
+ for (let l = s; l <= a; l++) {
3464
+ const o = i[l];
3465
+ o && !o.effectivelyDisabled && (this._values.add(o.value), o.selected = !0);
3466
+ }
3467
+ const r = Array.from(this._values);
3468
+ this.setAttribute("value", r.join(",")), this.emit("change", { value: r }), this.emit("a11y-listbox-change", { value: r }), p(`${a - s + 1} items selected`);
3469
+ }
3470
+ toggleSelectAll() {
3471
+ const e = this.getEnabledOptions();
3472
+ e.every((s) => this._values.has(s.value)) ? (this._values.clear(), this.getAllOptions().forEach((s) => s.selected = !1), p("All deselected")) : (e.forEach((s) => {
3473
+ this._values.add(s.value), s.selected = !0;
3474
+ }), p("All selected"));
3475
+ const i = Array.from(this._values);
3476
+ this.setAttribute("value", i.join(",")), this.emit("change", { value: i }), this.emit("a11y-listbox-change", { value: i });
3477
+ }
3478
+ // ===== Type-ahead =====
3479
+ rebuildTypeAhead() {
3480
+ const e = this.getAllOptions().map(
3481
+ (t) => {
3482
+ var i;
3483
+ return ((i = t.textContent) == null ? void 0 : i.trim()) || "";
3484
+ }
3485
+ );
3486
+ this._typeAhead = q(e, { timeout: 500 });
3487
+ }
3488
+ // ===== Attribute Changes =====
3489
+ attributeChangedCallback(e, t, i) {
3490
+ if (t !== i)
3491
+ switch (e) {
3492
+ case "value":
3493
+ this._multiple ? this._values = new Set(
3494
+ (i || "").split(",").filter(Boolean)
3495
+ ) : this._value = i || null, this.syncOptionStates();
3496
+ break;
3497
+ case "multiple":
3498
+ this._multiple = i !== null, this._multiple ? (this.setAttribute("aria-multiselectable", "true"), this._value && (this._values = /* @__PURE__ */ new Set([this._value]), this._value = null)) : (this.removeAttribute("aria-multiselectable"), this._values.size > 0 && (this._value = Array.from(this._values)[0] ?? null, this._values.clear())), this.syncOptionStates();
3499
+ break;
3500
+ case "disabled":
3501
+ this._disabled = i !== null, this._disabled ? (this.setAttribute("aria-disabled", "true"), this._discoverable || this.setAttribute("tabindex", "-1")) : (this.removeAttribute("aria-disabled"), this.setAttribute("tabindex", "0"));
3502
+ break;
3503
+ case "discoverable":
3504
+ i === null ? this._discoverable = !0 : i === "false" || i === "0" ? this._discoverable = !1 : this._discoverable = !0;
3505
+ break;
3506
+ case "orientation":
3507
+ (i === "horizontal" || i === "vertical") && (this._orientation = i, this.setAttribute("aria-orientation", i));
3508
+ break;
3509
+ }
1141
3510
  }
1142
3511
  }
1143
- d("a11y-combobox", v);
1144
- class w extends h {
3512
+ u("a11y-optgroup", X);
3513
+ u("a11y-option", V);
3514
+ u("a11y-listbox", W);
3515
+ const De = `<svg class="checkbox-check" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
3516
+ <path d="M2.5 6L5 8.5L9.5 3.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3517
+ </svg>`, Oe = `<svg class="checkbox-dash" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
3518
+ <path d="M3 6H9" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
3519
+ </svg>`;
3520
+ class O extends c {
1145
3521
  constructor() {
1146
- super(...arguments), this._checked = !1, this._button = null, this._label = null, this.handleClick = () => {
1147
- this.toggle();
1148
- }, this.handleKeyDown = (t) => {
1149
- this.disabled || (t.key === " " || t.key === "Enter") && (t.preventDefault(), this.toggle());
1150
- }, this.handleLabelClick = () => {
1151
- var t;
1152
- this.disabled || (this.toggle(), (t = this._button) == null || t.focus());
3522
+ super(...arguments), this._checked = !1, this._indeterminate = !1, this._input = null, this.handleChange = () => {
3523
+ if (!this._input) return;
3524
+ this._checked = this._input.checked, this.toggleAttribute("checked", this._checked), this._indeterminate && (this._indeterminate = !1, this.removeAttribute("indeterminate"), this._input.indeterminate = !1), this.updateVisualState(), this.emit("change", { checked: this._checked, value: this.value });
3525
+ const e = this.label || this.getAttribute("aria-label") || "Checkbox";
3526
+ p(`${e} ${this._checked ? "checked" : "unchecked"}`);
1153
3527
  };
1154
3528
  }
1155
3529
  static get observedAttributes() {
1156
- return ["checked", "disabled", "label", "size", "aria-label"];
3530
+ return [
3531
+ "checked",
3532
+ "indeterminate",
3533
+ "disabled",
3534
+ "label",
3535
+ "hint",
3536
+ "error",
3537
+ "value",
3538
+ "name",
3539
+ "required",
3540
+ "size",
3541
+ "aria-label",
3542
+ "aria-describedby"
3543
+ ];
1157
3544
  }
1158
3545
  /**
1159
3546
  * Get/set the checked state
@@ -1161,9 +3548,19 @@ class w extends h {
1161
3548
  get checked() {
1162
3549
  return this._checked;
1163
3550
  }
1164
- set checked(t) {
1165
- const e = this._checked;
1166
- this._checked = t, this.toggleAttribute("checked", t), t !== e && (this.updateVisualState(), this.emit("change", { checked: t }));
3551
+ set checked(e) {
3552
+ const t = this._checked;
3553
+ this._checked = e, this.toggleAttribute("checked", e), e !== t && (this.updateVisualState(), this.emit("change", { checked: e, value: this.value }));
3554
+ }
3555
+ /**
3556
+ * Get/set the indeterminate state
3557
+ */
3558
+ get indeterminate() {
3559
+ return this._indeterminate;
3560
+ }
3561
+ set indeterminate(e) {
3562
+ const t = this._indeterminate;
3563
+ this._indeterminate = e, this.toggleAttribute("indeterminate", e), e !== t && this.updateVisualState();
1167
3564
  }
1168
3565
  /**
1169
3566
  * Get/set the disabled state
@@ -1171,8 +3568,17 @@ class w extends h {
1171
3568
  get disabled() {
1172
3569
  return this.hasAttribute("disabled");
1173
3570
  }
1174
- set disabled(t) {
1175
- this.toggleAttribute("disabled", t), this.updateDisabledState();
3571
+ set disabled(e) {
3572
+ this.toggleAttribute("disabled", e), this.updateDisabledState();
3573
+ }
3574
+ /**
3575
+ * Get/set the value
3576
+ */
3577
+ get value() {
3578
+ return this.getAttribute("value") || "";
3579
+ }
3580
+ set value(e) {
3581
+ e ? this.setAttribute("value", e) : this.removeAttribute("value");
1176
3582
  }
1177
3583
  /**
1178
3584
  * Get/set the visible label
@@ -1180,67 +3586,115 @@ class w extends h {
1180
3586
  get label() {
1181
3587
  return this.getAttribute("label") || "";
1182
3588
  }
1183
- set label(t) {
1184
- t ? this.setAttribute("label", t) : this.removeAttribute("label");
3589
+ set label(e) {
3590
+ e ? this.setAttribute("label", e) : this.removeAttribute("label");
3591
+ }
3592
+ /**
3593
+ * Get/set the hint text
3594
+ */
3595
+ get hint() {
3596
+ return this.getAttribute("hint") || "";
3597
+ }
3598
+ set hint(e) {
3599
+ e ? this.setAttribute("hint", e) : this.removeAttribute("hint");
3600
+ }
3601
+ /**
3602
+ * Get/set the error message
3603
+ */
3604
+ get error() {
3605
+ return this.getAttribute("error") || "";
3606
+ }
3607
+ set error(e) {
3608
+ e ? this.setAttribute("error", e) : this.removeAttribute("error");
1185
3609
  }
1186
3610
  /**
1187
3611
  * Get/set the size variant
1188
3612
  */
1189
3613
  get size() {
1190
- const t = this.getAttribute("size");
1191
- return t === "sm" || t === "lg" ? t : "md";
3614
+ const e = this.getAttribute("size");
3615
+ return e === "sm" || e === "lg" ? e : "md";
3616
+ }
3617
+ set size(e) {
3618
+ this.setAttribute("size", e);
3619
+ }
3620
+ /**
3621
+ * Get/set required state
3622
+ */
3623
+ get required() {
3624
+ return this.hasAttribute("required");
1192
3625
  }
1193
- set size(t) {
1194
- this.setAttribute("size", t);
3626
+ set required(e) {
3627
+ this.toggleAttribute("required", e);
1195
3628
  }
1196
3629
  setupAccessibility() {
1197
- var t;
1198
- this.getAttribute("role"), typeof process < "u" && ((t = process.env) == null ? void 0 : t.NODE_ENV) !== "production" && !this.label && !this.getAttribute("aria-label") && console.warn(
1199
- `[compa11y/Switch] Switch has no accessible label. Add label="..." or aria-label="..." attribute.
1200
- 💡 Suggestion: <a11y-switch label="Enable feature"></a11y-switch>`
3630
+ var e;
3631
+ this._checked = this.hasAttribute("checked"), this._indeterminate = this.hasAttribute("indeterminate"), typeof process < "u" && ((e = process.env) == null ? void 0 : e.NODE_ENV) !== "production" && !this.label && !this.getAttribute("aria-label") && console.warn(
3632
+ `[compa11y/Checkbox] Checkbox has no accessible label. Add label="..." or aria-label="..." attribute.
3633
+ 💡 Suggestion: <a11y-checkbox label="Accept terms"></a11y-checkbox>`
1201
3634
  );
1202
3635
  }
1203
3636
  render() {
1204
- const t = this.attachShadow({ mode: "open" }), e = `${this._id}-label`, i = !!this.label, s = this.getAttribute("aria-label"), o = i ? "" : s ? `aria-label="${s}"` : "", a = i ? `aria-labelledby="${e}"` : "";
1205
- t.innerHTML = `
1206
- <style>${U}</style>
1207
- <div class="switch-wrapper size-${this.size}" part="wrapper">
1208
- <button
1209
- type="button"
1210
- role="switch"
1211
- aria-checked="${this._checked}"
1212
- ${o}
1213
- ${a}
1214
- ${this.disabled ? "disabled" : ""}
1215
- class="switch-track ${this._checked ? "checked" : ""}"
1216
- part="track"
1217
- tabindex="${this.disabled ? "-1" : "0"}"
1218
- >
1219
- <span class="switch-thumb" part="thumb" aria-hidden="true"></span>
1220
- </button>
1221
- ${i ? `<label id="${e}" class="switch-label ${this.disabled ? "disabled" : ""}" part="label">${this.label}</label>` : ""}
3637
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-input`, i = `${this._id}-label`, s = `${this._id}-hint`, a = `${this._id}-error`, r = !!this.label, l = !!this.hint, o = !!this.error, d = this.getAttribute("aria-label"), h = this.getAttribute("name") || "", g = this.getAttribute("aria-describedby") || "", m = [];
3638
+ g && m.push(g), l && m.push(s), o && m.push(a);
3639
+ const f = m.length ? `aria-describedby="${m.join(" ")}"` : "", _ = !r && d ? `aria-label="${d}"` : "";
3640
+ e.innerHTML = `
3641
+ <style>${Ie}</style>
3642
+ <div class="checkbox-wrapper size-${this.size}" part="wrapper">
3643
+ <div class="checkbox-control">
3644
+ <input
3645
+ type="checkbox"
3646
+ class="checkbox-input"
3647
+ id="${t}"
3648
+ ${h ? `name="${h}"` : ""}
3649
+ ${this.value ? `value="${this.value}"` : ""}
3650
+ ${this._checked ? "checked" : ""}
3651
+ ${this.disabled ? "disabled" : ""}
3652
+ ${this.required ? 'required aria-required="true"' : ""}
3653
+ ${f}
3654
+ ${_}
3655
+ ${o ? 'aria-invalid="true"' : ""}
3656
+ part="input"
3657
+ />
3658
+ <div class="checkbox-indicator" part="indicator" aria-hidden="true">
3659
+ ${De}
3660
+ ${Oe}
3661
+ </div>
3662
+ </div>
3663
+ ${r || l || o ? `<div class="checkbox-content">
3664
+ ${r ? `<label for="${t}" id="${i}" class="checkbox-label" part="label">${this.label}${this.required ? '<span class="checkbox-required" aria-hidden="true">*</span>' : ""}</label>` : ""}
3665
+ ${l ? `<div id="${s}" class="checkbox-hint" part="hint">${this.hint}</div>` : ""}
3666
+ ${o ? `<div id="${a}" class="checkbox-error" role="alert" part="error">${this.error}</div>` : ""}
3667
+ </div>` : ""}
1222
3668
  </div>
1223
- `, this._button = t.querySelector("button"), this._label = t.querySelector("label");
3669
+ `, this._input = e.querySelector("input"), this._input && this._indeterminate && (this._input.indeterminate = !0);
1224
3670
  }
1225
3671
  setupEventListeners() {
1226
- var t, e, i;
1227
- (t = this._button) == null || t.addEventListener("click", this.handleClick), (e = this._button) == null || e.addEventListener("keydown", this.handleKeyDown), (i = this._label) == null || i.addEventListener("click", this.handleLabelClick);
3672
+ var e;
3673
+ (e = this._input) == null || e.addEventListener("change", this.handleChange);
1228
3674
  }
1229
3675
  cleanupEventListeners() {
1230
- var t, e, i;
1231
- (t = this._button) == null || t.removeEventListener("click", this.handleClick), (e = this._button) == null || e.removeEventListener("keydown", this.handleKeyDown), (i = this._label) == null || i.removeEventListener("click", this.handleLabelClick);
3676
+ var e;
3677
+ (e = this._input) == null || e.removeEventListener("change", this.handleChange);
1232
3678
  }
1233
- onAttributeChange(t, e, i) {
1234
- switch (t) {
3679
+ onAttributeChange(e, t, i) {
3680
+ switch (e) {
1235
3681
  case "checked":
1236
3682
  this._checked = i !== null, this.updateVisualState();
1237
3683
  break;
3684
+ case "indeterminate":
3685
+ this._indeterminate = i !== null, this.updateVisualState();
3686
+ break;
1238
3687
  case "disabled":
1239
3688
  this.updateDisabledState();
1240
3689
  break;
1241
3690
  case "label":
3691
+ case "hint":
3692
+ case "error":
1242
3693
  case "aria-label":
1243
- this.shadowRoot && (this.shadowRoot.innerHTML = "", this.render(), this.setupEventListeners());
3694
+ case "aria-describedby":
3695
+ case "required":
3696
+ case "name":
3697
+ this.shadowRoot && (this.cleanupEventListeners(), this.shadowRoot.innerHTML = "", this.render(), this.setupEventListeners());
1244
3698
  break;
1245
3699
  case "size":
1246
3700
  this.updateSizeClass();
@@ -1248,105 +3702,607 @@ class w extends h {
1248
3702
  }
1249
3703
  }
1250
3704
  /**
1251
- * Update the visual state (checked class and aria-checked)
3705
+ * Update visual state of indicator
1252
3706
  */
1253
3707
  updateVisualState() {
1254
- this._button && (this._button.setAttribute("aria-checked", String(this._checked)), this._button.classList.toggle("checked", this._checked));
3708
+ this._input && (this._input.checked = this._checked, this._input.indeterminate = this._indeterminate);
1255
3709
  }
1256
3710
  /**
1257
- * Update the disabled state
3711
+ * Update disabled state
1258
3712
  */
1259
3713
  updateDisabledState() {
1260
- this._button && (this.disabled ? (this._button.setAttribute("disabled", ""), this._button.setAttribute("tabindex", "-1")) : (this._button.removeAttribute("disabled"), this._button.setAttribute("tabindex", "0"))), this._label && this._label.classList.toggle("disabled", this.disabled);
3714
+ this._input && (this.disabled ? this._input.setAttribute("disabled", "") : this._input.removeAttribute("disabled"));
1261
3715
  }
1262
3716
  /**
1263
- * Update the size class
3717
+ * Update size class
1264
3718
  */
1265
3719
  updateSizeClass() {
1266
- var e;
1267
- const t = (e = this.shadowRoot) == null ? void 0 : e.querySelector(".switch-wrapper");
1268
- t && (t.classList.remove("size-sm", "size-md", "size-lg"), t.classList.add(`size-${this.size}`));
3720
+ var t;
3721
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector(".checkbox-wrapper");
3722
+ e && (e.classList.remove("size-sm", "size-md", "size-lg"), e.classList.add(`size-${this.size}`));
1269
3723
  }
1270
3724
  /**
1271
- * Public method to toggle the switch programmatically
3725
+ * Toggle the checkbox programmatically
1272
3726
  */
1273
3727
  toggle() {
1274
3728
  if (this.disabled) return;
1275
- this.checked = !this.checked;
1276
- const t = this.label || this.getAttribute("aria-label") || "Switch";
1277
- g(`${t} ${this.checked ? "on" : "off"}`);
3729
+ this._indeterminate ? (this.indeterminate = !1, this.checked = !0) : this.checked = !this.checked;
3730
+ const e = this.label || this.getAttribute("aria-label") || "Checkbox";
3731
+ p(`${e} ${this.checked ? "checked" : "unchecked"}`);
1278
3732
  }
1279
3733
  /**
1280
- * Public method to open/close programmatically
3734
+ * Set checked state programmatically
3735
+ */
3736
+ setChecked(e) {
3737
+ this.checked = e;
3738
+ }
3739
+ }
3740
+ class J extends c {
3741
+ constructor() {
3742
+ super(...arguments), this._value = [], this.handleChildChange = (e) => {
3743
+ const t = e.target;
3744
+ if (!(t instanceof O) || t === this) return;
3745
+ const i = t.value;
3746
+ i && (t.checked ? this._value.includes(i) || (this._value = [...this._value, i]) : this._value = this._value.filter((s) => s !== i), this.emit("change", { value: this._value }));
3747
+ };
3748
+ }
3749
+ static get observedAttributes() {
3750
+ return [
3751
+ "disabled",
3752
+ "legend",
3753
+ "error",
3754
+ "orientation",
3755
+ "aria-label",
3756
+ "aria-labelledby"
3757
+ ];
3758
+ }
3759
+ /**
3760
+ * Get/set the selected values as an array
3761
+ */
3762
+ get value() {
3763
+ return [...this._value];
3764
+ }
3765
+ set value(e) {
3766
+ this._value = [...e], this.syncCheckboxStates();
3767
+ }
3768
+ /**
3769
+ * Get/set the disabled state
3770
+ */
3771
+ get disabled() {
3772
+ return this.hasAttribute("disabled");
3773
+ }
3774
+ set disabled(e) {
3775
+ this.toggleAttribute("disabled", e), this.syncDisabledState();
3776
+ }
3777
+ /**
3778
+ * Get/set the legend text
3779
+ */
3780
+ get legend() {
3781
+ return this.getAttribute("legend") || "";
3782
+ }
3783
+ set legend(e) {
3784
+ e ? this.setAttribute("legend", e) : this.removeAttribute("legend");
3785
+ }
3786
+ /**
3787
+ * Get/set the error message
3788
+ */
3789
+ get error() {
3790
+ return this.getAttribute("error") || "";
3791
+ }
3792
+ set error(e) {
3793
+ e ? this.setAttribute("error", e) : this.removeAttribute("error");
3794
+ }
3795
+ /**
3796
+ * Get/set the orientation
3797
+ */
3798
+ get orientation() {
3799
+ return this.getAttribute("orientation") === "horizontal" ? "horizontal" : "vertical";
3800
+ }
3801
+ set orientation(e) {
3802
+ this.setAttribute("orientation", e);
3803
+ }
3804
+ setupAccessibility() {
3805
+ var e;
3806
+ typeof process < "u" && ((e = process.env) == null ? void 0 : e.NODE_ENV) !== "production" && !this.legend && !this.getAttribute("aria-label") && !this.getAttribute("aria-labelledby") && console.warn(
3807
+ `[compa11y/CheckboxGroup] CheckboxGroup has no accessible label. Add legend="..." or aria-label="..." attribute.
3808
+ 💡 Suggestion: <a11y-checkbox-group legend="Select options"></a11y-checkbox-group>`
3809
+ ), this.initValueFromChildren();
3810
+ }
3811
+ render() {
3812
+ const e = this.attachShadow({ mode: "open" }), t = `${this._id}-error`, i = !!this.legend, s = !!this.error, a = this.getAttribute("aria-label"), r = this.getAttribute("aria-labelledby");
3813
+ e.innerHTML = `
3814
+ <style>${Ce}</style>
3815
+ <fieldset
3816
+ part="fieldset"
3817
+ ${a ? `aria-label="${a}"` : ""}
3818
+ ${r ? `aria-labelledby="${r}"` : ""}
3819
+ ${s ? `aria-describedby="${t}"` : ""}
3820
+ ${this.disabled ? "disabled" : ""}
3821
+ >
3822
+ ${i ? `<legend part="legend">${this.legend}</legend>` : ""}
3823
+ <div class="checkbox-group-items" part="items">
3824
+ <slot></slot>
3825
+ </div>
3826
+ ${s ? `<div id="${t}" class="checkbox-group-error" role="alert" part="error">${this.error}</div>` : ""}
3827
+ </fieldset>
3828
+ `;
3829
+ }
3830
+ setupEventListeners() {
3831
+ this.addEventListener("change", this.handleChildChange);
3832
+ }
3833
+ cleanupEventListeners() {
3834
+ this.removeEventListener("change", this.handleChildChange);
3835
+ }
3836
+ onAttributeChange(e, t, i) {
3837
+ switch (e) {
3838
+ case "disabled":
3839
+ this.syncDisabledState();
3840
+ break;
3841
+ case "legend":
3842
+ case "error":
3843
+ case "aria-label":
3844
+ case "aria-labelledby":
3845
+ this.shadowRoot && (this.cleanupEventListeners(), this.shadowRoot.innerHTML = "", this.render(), this.setupEventListeners());
3846
+ break;
3847
+ }
3848
+ }
3849
+ /**
3850
+ * Initialize value array from currently checked children
3851
+ */
3852
+ initValueFromChildren() {
3853
+ requestAnimationFrame(() => {
3854
+ const e = this.querySelectorAll("a11y-checkbox"), t = [];
3855
+ e.forEach((i) => {
3856
+ i.hasAttribute("checked") && i.getAttribute("value") && t.push(i.getAttribute("value"));
3857
+ }), this._value = t;
3858
+ });
3859
+ }
3860
+ /**
3861
+ * Sync checkbox checked states from value array
3862
+ */
3863
+ syncCheckboxStates() {
3864
+ this.querySelectorAll(
3865
+ "a11y-checkbox"
3866
+ ).forEach((t) => {
3867
+ const i = t.value;
3868
+ i && (t.checked = this._value.includes(i));
3869
+ });
3870
+ }
3871
+ /**
3872
+ * Sync disabled state to children
1281
3873
  */
1282
- setChecked(t) {
1283
- this.checked = t;
3874
+ syncDisabledState() {
3875
+ var t;
3876
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector("fieldset");
3877
+ e && (this.disabled ? e.setAttribute("disabled", "") : e.removeAttribute("disabled"));
3878
+ }
3879
+ }
3880
+ u("a11y-checkbox", O);
3881
+ u("a11y-checkbox-group", J);
3882
+ class Q extends c {
3883
+ constructor() {
3884
+ super(...arguments), this._value = "", this._disabled = !1, this._discoverable = !0, this._orientation = "vertical", this._required = !1, this._name = "", this.handleRadioSelect = (e) => {
3885
+ var i;
3886
+ if (this._disabled) return;
3887
+ const t = (i = e.detail) == null ? void 0 : i.value;
3888
+ t !== void 0 && this.selectRadio(t);
3889
+ }, this.handleKeyDown = (e) => {
3890
+ if (this._disabled) return;
3891
+ const t = this.getEnabledRadios();
3892
+ if (t.length === 0) return;
3893
+ const i = t.findIndex(
3894
+ (a) => a.value === this._value
3895
+ );
3896
+ let s = null;
3897
+ switch (e.key) {
3898
+ case "ArrowDown":
3899
+ case "ArrowRight":
3900
+ s = i < 0 ? 0 : (i + 1) % t.length;
3901
+ break;
3902
+ case "ArrowUp":
3903
+ case "ArrowLeft":
3904
+ s = i < 0 ? t.length - 1 : (i - 1 + t.length) % t.length;
3905
+ break;
3906
+ case "Home":
3907
+ s = 0;
3908
+ break;
3909
+ case "End":
3910
+ s = t.length - 1;
3911
+ break;
3912
+ case " ":
3913
+ e.preventDefault(), e.stopPropagation();
3914
+ {
3915
+ const a = t.find(
3916
+ (r) => r === document.activeElement || r.contains(document.activeElement)
3917
+ );
3918
+ if (a && a.value !== this._value) {
3919
+ this.selectRadio(a.value);
3920
+ const r = a.getAttribute("label") || a.value;
3921
+ p(`${r} selected`);
3922
+ }
3923
+ }
3924
+ return;
3925
+ default:
3926
+ return;
3927
+ }
3928
+ if (s !== null) {
3929
+ e.preventDefault(), e.stopPropagation();
3930
+ const a = t[s];
3931
+ if (a) {
3932
+ this.selectRadio(a.value), a.focus();
3933
+ const r = a.getAttribute("label") || a.value;
3934
+ p(`${r} selected`);
3935
+ }
3936
+ }
3937
+ };
3938
+ }
3939
+ static get observedAttributes() {
3940
+ return [
3941
+ "value",
3942
+ "disabled",
3943
+ "discoverable",
3944
+ "orientation",
3945
+ "required",
3946
+ "name",
3947
+ "legend",
3948
+ "hint",
3949
+ "error",
3950
+ "aria-label",
3951
+ "aria-labelledby"
3952
+ ];
3953
+ }
3954
+ // ===== Getters/Setters =====
3955
+ get value() {
3956
+ return this._value;
3957
+ }
3958
+ set value(e) {
3959
+ this._value !== e && (this._value = e, this.setAttribute("value", e), this.syncRadioStates());
3960
+ }
3961
+ get disabled() {
3962
+ return this._disabled;
3963
+ }
3964
+ set disabled(e) {
3965
+ const t = !!e;
3966
+ this._disabled !== t && (this._disabled = t, t ? (this.setAttribute("disabled", ""), this.setAttribute("aria-disabled", "true")) : (this.removeAttribute("disabled"), this.removeAttribute("aria-disabled")), this.syncRadioStates());
3967
+ }
3968
+ get discoverable() {
3969
+ return this._discoverable;
3970
+ }
3971
+ set discoverable(e) {
3972
+ this._discoverable = !!e;
3973
+ }
3974
+ get required() {
3975
+ return this._required;
3976
+ }
3977
+ set required(e) {
3978
+ this._required = !!e, this._required ? this.setAttribute("aria-required", "true") : this.removeAttribute("aria-required");
3979
+ }
3980
+ get name() {
3981
+ return this._name;
3982
+ }
3983
+ set name(e) {
3984
+ this._name = e, this.setAttribute("name", e);
3985
+ }
3986
+ get orientation() {
3987
+ return this._orientation;
3988
+ }
3989
+ set orientation(e) {
3990
+ this._orientation = e, this.setAttribute("orientation", e), this.setAttribute("aria-orientation", e);
3991
+ }
3992
+ // ===== Lifecycle =====
3993
+ setupAccessibility() {
3994
+ this.setAttribute("role", "radiogroup"), this.setAttribute("aria-orientation", this._orientation), !(this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby") || this.hasAttribute("legend")) && process.env.NODE_ENV !== "production" && console.warn(
3995
+ "[Compa11y RadioGroup]: RadioGroup has no accessible label. Use legend, aria-label, or aria-labelledby."
3996
+ );
3997
+ const t = this.getAttribute("value");
3998
+ t && (this._value = t), this._disabled = this.hasAttribute("disabled"), this._disabled && this.setAttribute("aria-disabled", "true");
3999
+ const i = this.getAttribute("orientation");
4000
+ (i === "horizontal" || i === "vertical") && (this._orientation = i), this._required = this.hasAttribute("required"), this._required && this.setAttribute("aria-required", "true"), this._name = this.getAttribute("name") || this._id;
4001
+ const s = this.getAttribute("discoverable");
4002
+ (s === "false" || s === "0") && (this._discoverable = !1), this.hasAttribute("error") && this.getAttribute("error") && this.setAttribute("aria-invalid", "true");
4003
+ }
4004
+ render() {
4005
+ this.shadowRoot || this.attachShadow({ mode: "open" });
4006
+ const e = this.shadowRoot, t = this.getAttribute("legend") || "", i = this.getAttribute("hint") || "", s = this.getAttribute("error") || "", a = i ? `${this._id}-hint` : "", r = s ? `${this._id}-error` : "", l = [a, r].filter(Boolean).join(" ");
4007
+ l ? this.setAttribute("aria-describedby", l) : this.removeAttribute("aria-describedby"), e.innerHTML = `
4008
+ <style>${ze}</style>
4009
+ <fieldset part="fieldset">
4010
+ ${t ? `<legend part="legend">${t}${this._required ? '<span class="radio-group-required" aria-hidden="true"> *</span>' : ""}</legend>` : ""}
4011
+ <div class="radio-group-items" part="items">
4012
+ <slot></slot>
4013
+ </div>
4014
+ ${i ? `<div class="radio-group-hint" id="${a}" part="hint">${i}</div>` : ""}
4015
+ ${s ? `<div class="radio-group-error" id="${r}" part="error" role="alert">${s}</div>` : ""}
4016
+ </fieldset>
4017
+ `;
4018
+ }
4019
+ setupEventListeners() {
4020
+ var t;
4021
+ this.addEventListener("keydown", this.handleKeyDown), this.addEventListener(
4022
+ "radio-select",
4023
+ this.handleRadioSelect
4024
+ );
4025
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector("slot");
4026
+ e && e.addEventListener("slotchange", () => {
4027
+ this.syncRadioStates();
4028
+ });
4029
+ }
4030
+ cleanupEventListeners() {
4031
+ this.removeEventListener("keydown", this.handleKeyDown), this.removeEventListener(
4032
+ "radio-select",
4033
+ this.handleRadioSelect
4034
+ );
4035
+ }
4036
+ // ===== Radio Management =====
4037
+ getRadios() {
4038
+ return Array.from(this.querySelectorAll("a11y-radio"));
4039
+ }
4040
+ getEnabledRadios() {
4041
+ return this.getRadios().filter(
4042
+ (e) => !e.disabled && !this._disabled
4043
+ );
4044
+ }
4045
+ syncRadioStates() {
4046
+ const e = this.getRadios(), t = this.getEnabledRadios();
4047
+ e.forEach((i) => {
4048
+ const s = i.value === this._value;
4049
+ i.checked = s, s || !this._value && t[0] === i ? i.setAttribute("tabindex", "0") : i.setAttribute("tabindex", "-1");
4050
+ });
4051
+ }
4052
+ selectRadio(e) {
4053
+ this._disabled || (this._value = e, this.setAttribute("value", e), this.syncRadioStates(), this.hasAttribute("aria-invalid") && this.removeAttribute("aria-invalid"), this.emit("change", { value: e }), this.emit("a11y-radiogroup-change", { value: e }));
4054
+ }
4055
+ // ===== Attribute Changes =====
4056
+ attributeChangedCallback(e, t, i) {
4057
+ if (t !== i)
4058
+ switch (e) {
4059
+ case "value":
4060
+ this._value = i || "", this.syncRadioStates();
4061
+ break;
4062
+ case "disabled":
4063
+ this._disabled = i !== null, this._disabled ? this.setAttribute("aria-disabled", "true") : this.removeAttribute("aria-disabled"), this.syncRadioStates();
4064
+ break;
4065
+ case "discoverable":
4066
+ i === null ? this._discoverable = !0 : i === "false" || i === "0" ? this._discoverable = !1 : this._discoverable = !0;
4067
+ break;
4068
+ case "orientation":
4069
+ (i === "horizontal" || i === "vertical") && (this._orientation = i, this.setAttribute("aria-orientation", i));
4070
+ break;
4071
+ case "required":
4072
+ this._required = i !== null, this._required ? this.setAttribute("aria-required", "true") : this.removeAttribute("aria-required");
4073
+ break;
4074
+ case "name":
4075
+ this._name = i || "";
4076
+ break;
4077
+ case "error":
4078
+ i ? this.setAttribute("aria-invalid", "true") : this.removeAttribute("aria-invalid"), this.render();
4079
+ break;
4080
+ case "legend":
4081
+ case "hint":
4082
+ this.render();
4083
+ break;
4084
+ }
4085
+ }
4086
+ }
4087
+ class Z extends c {
4088
+ constructor() {
4089
+ super(...arguments), this._value = "", this._checked = !1, this._disabled = !1, this._discoverable = !0, this.handleClick = (e) => {
4090
+ if (this._disabled) {
4091
+ e.preventDefault();
4092
+ return;
4093
+ }
4094
+ this.dispatchEvent(
4095
+ new CustomEvent("radio-select", {
4096
+ detail: { value: this._value },
4097
+ bubbles: !0,
4098
+ composed: !0
4099
+ })
4100
+ );
4101
+ const t = this.getAttribute("label") || this._value;
4102
+ p(`${t} selected`);
4103
+ }, this.handleKeyDown = (e) => {
4104
+ if (!this._disabled && e.key === "Enter") {
4105
+ e.preventDefault(), this.dispatchEvent(
4106
+ new CustomEvent("radio-select", {
4107
+ detail: { value: this._value },
4108
+ bubbles: !0,
4109
+ composed: !0
4110
+ })
4111
+ );
4112
+ const t = this.getAttribute("label") || this._value;
4113
+ p(`${t} selected`);
4114
+ }
4115
+ };
4116
+ }
4117
+ static get observedAttributes() {
4118
+ return ["value", "label", "hint", "disabled", "discoverable", "checked"];
4119
+ }
4120
+ // ===== Getters/Setters =====
4121
+ get value() {
4122
+ return this._value;
4123
+ }
4124
+ set value(e) {
4125
+ this._value = e, this.setAttribute("value", e);
4126
+ }
4127
+ get checked() {
4128
+ return this._checked;
4129
+ }
4130
+ set checked(e) {
4131
+ const t = !!e;
4132
+ this._checked !== t && (this._checked = t, t ? this.setAttribute("checked", "") : this.removeAttribute("checked"), this.setAttribute("aria-checked", String(t)), this.updateVisual());
4133
+ }
4134
+ get disabled() {
4135
+ return this._disabled;
4136
+ }
4137
+ set disabled(e) {
4138
+ const t = !!e;
4139
+ this._disabled !== t && (this._disabled = t, t ? (this.setAttribute("disabled", ""), this.setAttribute("aria-disabled", "true")) : (this.removeAttribute("disabled"), this.removeAttribute("aria-disabled")));
4140
+ }
4141
+ get discoverable() {
4142
+ return this._discoverable;
4143
+ }
4144
+ set discoverable(e) {
4145
+ let t;
4146
+ typeof e == "string" ? t = e !== "false" && e !== "0" : t = !!e, this._discoverable !== t && (this._discoverable = t, t ? this.setAttribute("discoverable", "") : this.removeAttribute("discoverable"));
4147
+ }
4148
+ // ===== Lifecycle =====
4149
+ setupAccessibility() {
4150
+ this.setAttribute("role", "radio"), this.setAttribute("aria-checked", "false"), this._value = this.getAttribute("value") || "", this._checked = this.hasAttribute("checked"), this._disabled = this.hasAttribute("disabled"), this._checked && this.setAttribute("aria-checked", "true"), this._disabled && this.setAttribute("aria-disabled", "true");
4151
+ const e = this.getAttribute("discoverable");
4152
+ (e === "false" || e === "0") && (this._discoverable = !1), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "-1");
4153
+ }
4154
+ render() {
4155
+ this.shadowRoot || this.attachShadow({ mode: "open" });
4156
+ const e = this.shadowRoot, t = this.getAttribute("label") || "", i = this.getAttribute("hint") || "", s = t ? `${this._id}-label` : "", a = i ? `${this._id}-hint` : "";
4157
+ s && this.setAttribute("aria-labelledby", s), a && this.setAttribute("aria-describedby", a), e.innerHTML = `
4158
+ <style>${qe}</style>
4159
+ <div class="radio-wrapper" part="wrapper">
4160
+ <div class="radio-control" part="control">
4161
+ <input
4162
+ type="radio"
4163
+ class="radio-input"
4164
+ tabindex="-1"
4165
+ aria-hidden="true"
4166
+ ${this._disabled ? "disabled" : ""}
4167
+ />
4168
+ <div class="radio-circle" part="circle">
4169
+ <div class="radio-dot" part="dot" aria-hidden="true"></div>
4170
+ </div>
4171
+ </div>
4172
+ ${t || i ? `<div class="radio-content">
4173
+ ${t ? `<span class="radio-label" id="${s}" part="label">${t}</span>` : ""}
4174
+ ${i ? `<span class="radio-hint" id="${a}" part="hint">${i}</span>` : ""}
4175
+ </div>` : ""}
4176
+ <slot></slot>
4177
+ </div>
4178
+ `;
4179
+ }
4180
+ setupEventListeners() {
4181
+ this.addEventListener("click", this.handleClick), this.addEventListener("keydown", this.handleKeyDown);
4182
+ }
4183
+ cleanupEventListeners() {
4184
+ this.removeEventListener("click", this.handleClick), this.removeEventListener("keydown", this.handleKeyDown);
4185
+ }
4186
+ // ===== Visual Update =====
4187
+ updateVisual() {
4188
+ if (!this.shadowRoot) return;
4189
+ const e = this.shadowRoot.querySelector(".radio-dot");
4190
+ e && (e.style.opacity = this._checked ? "1" : "0", e.style.transform = this._checked ? "scale(1)" : "scale(0)");
4191
+ const t = this.shadowRoot.querySelector(
4192
+ ".radio-circle"
4193
+ );
4194
+ t && (this._checked ? (t.style.background = "var(--compa11y-radio-checked-bg, #0066cc)", t.style.borderColor = "var(--compa11y-radio-checked-border, #0066cc)") : (t.style.background = "var(--compa11y-radio-bg, white)", t.style.borderColor = ""));
4195
+ }
4196
+ // ===== Attribute Changes =====
4197
+ attributeChangedCallback(e, t, i) {
4198
+ if (t !== i)
4199
+ switch (e) {
4200
+ case "value":
4201
+ this._value = i || "";
4202
+ break;
4203
+ case "checked":
4204
+ this._checked = i !== null, this.setAttribute("aria-checked", String(this._checked)), this.updateVisual();
4205
+ break;
4206
+ case "disabled":
4207
+ this._disabled = i !== null, this._disabled ? this.setAttribute("aria-disabled", "true") : this.removeAttribute("aria-disabled");
4208
+ break;
4209
+ case "discoverable":
4210
+ i === null ? this._discoverable = !0 : i === "false" || i === "0" ? this._discoverable = !1 : this._discoverable = !0;
4211
+ break;
4212
+ case "label":
4213
+ case "hint":
4214
+ this.render();
4215
+ break;
4216
+ }
1284
4217
  }
1285
4218
  }
1286
- d("a11y-switch", w);
4219
+ u("a11y-radio-group", Q);
4220
+ u("a11y-radio", Z);
1287
4221
  if (typeof window < "u") {
1288
4222
  const n = () => {
1289
- b(), p();
4223
+ R(), T();
1290
4224
  };
1291
4225
  document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", n) : n(), window.compa11y = {
1292
4226
  // Components (classes)
1293
- A11yDialog: y,
1294
- A11yMenu: _,
1295
- A11yTabs: x,
1296
- A11yCombobox: v,
1297
- A11ySwitch: w,
4227
+ A11yDialog: M,
4228
+ A11yMenu: K,
4229
+ A11yTabs: F,
4230
+ A11yCombobox: N,
4231
+ A11ySwitch: P,
4232
+ A11ySelect: j,
4233
+ A11yInput: U,
4234
+ A11yTextarea: Y,
4235
+ A11yButton: G,
4236
+ A11yListbox: W,
4237
+ A11yOption: V,
4238
+ A11yOptgroup: X,
4239
+ A11yCheckbox: O,
4240
+ A11yCheckboxGroup: J,
4241
+ A11yRadioGroup: Q,
4242
+ A11yRadio: Z,
1298
4243
  // Announcer utilities
1299
- initAnnouncer: b,
1300
- announce: r,
1301
- announcePolite: g,
1302
- announceAssertive: V,
1303
- announceStatus: H,
1304
- announceError: R,
4244
+ initAnnouncer: R,
4245
+ announce: v,
4246
+ announcePolite: p,
4247
+ announceAssertive: D,
4248
+ announceStatus: ge,
4249
+ announceError: pe,
1305
4250
  // Focus utilities
1306
- initFocusVisible: p,
1307
- createFocusTrap: M,
1308
- createFocusScope: q,
1309
- createRovingTabindex: z,
4251
+ initFocusVisible: T,
4252
+ createFocusTrap: be,
4253
+ createFocusScope: ue,
4254
+ createRovingTabindex: ce,
1310
4255
  // Keyboard utilities
1311
- createKeyboardManager: O,
1312
- KeyboardPatterns: D,
1313
- createTypeAhead: T,
4256
+ createKeyboardManager: de,
4257
+ KeyboardPatterns: he,
4258
+ createTypeAhead: q,
1314
4259
  // ARIA utilities
1315
- aria: $,
1316
- buildAriaProps: C,
1317
- hasAccessibleName: S,
4260
+ aria: ne,
4261
+ buildAriaProps: le,
4262
+ hasAccessibleName: oe,
1318
4263
  // Platform detection
1319
- isBrowser: L,
1320
- prefersReducedMotion: I,
1321
- prefersHighContrast: A,
1322
- prefersDarkMode: k
4264
+ isBrowser: re,
4265
+ prefersReducedMotion: ae,
4266
+ prefersHighContrast: se,
4267
+ prefersDarkMode: ie
1323
4268
  };
1324
4269
  }
1325
4270
  export {
1326
- v as A11yCombobox,
1327
- y as A11yDialog,
1328
- _ as A11yMenu,
1329
- w as A11ySwitch,
1330
- x as A11yTabs,
1331
- G as KeyboardPatterns,
1332
- W as announce,
1333
- J as announceAssertive,
1334
- Q as announceError,
1335
- Z as announcePolite,
1336
- tt as announceStatus,
1337
- et as aria,
1338
- it as buildAriaProps,
1339
- st as createFocusScope,
1340
- ot as createFocusTrap,
1341
- at as createKeyboardManager,
1342
- nt as createRovingTabindex,
1343
- lt as createTypeAhead,
1344
- rt as hasAccessibleName,
1345
- ht as initAnnouncer,
1346
- dt as initFocusVisible,
1347
- ct as isBrowser,
1348
- ut as prefersDarkMode,
1349
- pt as prefersHighContrast,
1350
- bt as prefersReducedMotion
4271
+ G as A11yButton,
4272
+ O as A11yCheckbox,
4273
+ J as A11yCheckboxGroup,
4274
+ N as A11yCombobox,
4275
+ M as A11yDialog,
4276
+ U as A11yInput,
4277
+ W as A11yListbox,
4278
+ K as A11yMenu,
4279
+ X as A11yOptgroup,
4280
+ V as A11yOption,
4281
+ Z as A11yRadio,
4282
+ Q as A11yRadioGroup,
4283
+ j as A11ySelect,
4284
+ P as A11ySwitch,
4285
+ F as A11yTabs,
4286
+ Y as A11yTextarea,
4287
+ He as KeyboardPatterns,
4288
+ Me as announce,
4289
+ Ke as announceAssertive,
4290
+ Fe as announceError,
4291
+ Ne as announcePolite,
4292
+ Pe as announceStatus,
4293
+ je as aria,
4294
+ Ue as buildAriaProps,
4295
+ Ye as createFocusScope,
4296
+ Ge as createFocusTrap,
4297
+ Xe as createKeyboardManager,
4298
+ Ve as createRovingTabindex,
4299
+ We as createTypeAhead,
4300
+ Je as hasAccessibleName,
4301
+ Qe as initAnnouncer,
4302
+ Ze as initFocusVisible,
4303
+ et as isBrowser,
4304
+ tt as prefersDarkMode,
4305
+ it as prefersHighContrast,
4306
+ st as prefersReducedMotion
1351
4307
  };
1352
4308
  //# sourceMappingURL=compa11y.js.map