@compa11y/web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1352 @@
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 {
4
+ constructor() {
5
+ super(), this._internals = null, this._id = E(this.tagName.toLowerCase().replace("a11y-", "")), "attachInternals" in this && (this._internals = this.attachInternals());
6
+ }
7
+ /**
8
+ * Standard observed attributes
9
+ */
10
+ static get observedAttributes() {
11
+ return [];
12
+ }
13
+ /**
14
+ * Called when element is added to DOM
15
+ */
16
+ connectedCallback() {
17
+ this.setupAccessibility(), this.render(), this.setupEventListeners();
18
+ }
19
+ /**
20
+ * Called when element is removed from DOM
21
+ */
22
+ disconnectedCallback() {
23
+ this.cleanupEventListeners();
24
+ }
25
+ /**
26
+ * Called when observed attributes change
27
+ */
28
+ attributeChangedCallback(t, e, i) {
29
+ e !== i && this.onAttributeChange(t, e, i);
30
+ }
31
+ /**
32
+ * Set up event listeners
33
+ */
34
+ setupEventListeners() {
35
+ }
36
+ /**
37
+ * Clean up event listeners
38
+ */
39
+ cleanupEventListeners() {
40
+ }
41
+ /**
42
+ * Handle attribute changes
43
+ */
44
+ onAttributeChange(t, e, i) {
45
+ }
46
+ /**
47
+ * Emit a custom event
48
+ */
49
+ emit(t, e) {
50
+ return this.dispatchEvent(
51
+ new CustomEvent(t, {
52
+ detail: e,
53
+ bubbles: !0,
54
+ composed: !0,
55
+ cancelable: !0
56
+ })
57
+ );
58
+ }
59
+ /**
60
+ * Query a slot
61
+ */
62
+ getSlot(t) {
63
+ var e;
64
+ return ((e = this.shadowRoot) == null ? void 0 : e.querySelector(`slot[name="${t}"]`)) ?? null;
65
+ }
66
+ /**
67
+ * Get slotted elements
68
+ */
69
+ getSlottedElements(t) {
70
+ var s;
71
+ const e = t ? `slot[name="${t}"]` : "slot:not([name])", i = (s = this.shadowRoot) == null ? void 0 : s.querySelector(
72
+ e
73
+ );
74
+ return (i == null ? void 0 : i.assignedElements()) ?? [];
75
+ }
76
+ }
77
+ function d(n, t) {
78
+ customElements.get(n) || customElements.define(n, t);
79
+ }
80
+ const f = `
81
+ appearance: none;
82
+ background: none;
83
+ border: none;
84
+ padding: 0;
85
+ margin: 0;
86
+ font: inherit;
87
+ color: inherit;
88
+ cursor: pointer;
89
+ `, K = `
90
+ :host(:focus-visible),
91
+ :focus-visible {
92
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
93
+ outline-offset: 2px;
94
+ }
95
+ `, c = `
96
+ :host {
97
+ display: block;
98
+ box-sizing: border-box;
99
+ }
100
+
101
+ :host([hidden]) {
102
+ display: none !important;
103
+ }
104
+
105
+ *,
106
+ *::before,
107
+ *::after {
108
+ box-sizing: inherit;
109
+ }
110
+
111
+ ${K}
112
+ `, B = `
113
+ ${c}
114
+
115
+ :host {
116
+ position: fixed;
117
+ inset: 0;
118
+ z-index: var(--compa11y-dialog-z-index, 9999);
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ }
123
+
124
+ .overlay {
125
+ position: absolute;
126
+ inset: 0;
127
+ background: var(--compa11y-dialog-overlay-bg, rgba(0, 0, 0, 0.5));
128
+ }
129
+
130
+ .dialog {
131
+ position: relative;
132
+ background: var(--compa11y-dialog-bg, white);
133
+ border-radius: var(--compa11y-dialog-radius, 8px);
134
+ padding: var(--compa11y-dialog-padding, 1.5rem);
135
+ max-width: var(--compa11y-dialog-max-width, 500px);
136
+ max-height: var(--compa11y-dialog-max-height, 85vh);
137
+ overflow: auto;
138
+ box-shadow: var(--compa11y-dialog-shadow, 0 25px 50px -12px rgba(0, 0, 0, 0.25));
139
+ }
140
+
141
+ ::slotted([slot="title"]) {
142
+ margin: 0 0 0.5rem 0;
143
+ font-size: 1.25rem;
144
+ font-weight: 600;
145
+ }
146
+
147
+ ::slotted([slot="description"]) {
148
+ margin: 0 0 1rem 0;
149
+ color: var(--compa11y-dialog-description-color, #666);
150
+ }
151
+ `, F = `
152
+ ${c}
153
+
154
+ :host {
155
+ position: relative;
156
+ display: inline-block;
157
+ }
158
+
159
+ .menu-content {
160
+ position: absolute;
161
+ top: 100%;
162
+ left: 0;
163
+ z-index: var(--compa11y-menu-z-index, 1000);
164
+ min-width: var(--compa11y-menu-min-width, 160px);
165
+ background: var(--compa11y-menu-bg, white);
166
+ border: var(--compa11y-menu-border, 1px solid #e0e0e0);
167
+ border-radius: var(--compa11y-menu-radius, 4px);
168
+ box-shadow: var(--compa11y-menu-shadow, 0 4px 6px -1px rgba(0, 0, 0, 0.1));
169
+ padding: var(--compa11y-menu-padding, 0.25rem 0);
170
+ margin-top: var(--compa11y-menu-offset, 4px);
171
+ }
172
+
173
+ .menu-content[hidden] {
174
+ display: none;
175
+ }
176
+
177
+ ::slotted([role="menuitem"]) {
178
+ display: block;
179
+ width: 100%;
180
+ padding: 0.5rem 1rem;
181
+ text-align: left;
182
+ background: none;
183
+ border: none;
184
+ cursor: pointer;
185
+ font: inherit;
186
+ }
187
+
188
+ ::slotted([role="menuitem"]:hover),
189
+ ::slotted([role="menuitem"][data-highlighted="true"]) {
190
+ background: var(--compa11y-menu-item-hover-bg, #f5f5f5);
191
+ }
192
+
193
+ ::slotted([role="menuitem"][aria-disabled="true"]) {
194
+ opacity: 0.5;
195
+ cursor: not-allowed;
196
+ }
197
+
198
+ ::slotted([role="separator"]) {
199
+ height: 1px;
200
+ margin: 0.25rem 0;
201
+ background: var(--compa11y-menu-separator-color, #e0e0e0);
202
+ }
203
+ `, P = `
204
+ ${c}
205
+
206
+ .tablist {
207
+ display: flex;
208
+ border-bottom: var(--compa11y-tabs-border, 1px solid #e0e0e0);
209
+ gap: var(--compa11y-tabs-gap, 0);
210
+ }
211
+
212
+ :host([orientation="vertical"]) .tablist {
213
+ flex-direction: column;
214
+ border-bottom: none;
215
+ border-right: var(--compa11y-tabs-border, 1px solid #e0e0e0);
216
+ }
217
+
218
+ ::slotted([role="tab"]) {
219
+ ${f}
220
+ padding: var(--compa11y-tab-padding, 0.75rem 1rem);
221
+ border-bottom: 2px solid transparent;
222
+ margin-bottom: -1px;
223
+ font-weight: 500;
224
+ color: var(--compa11y-tab-color, #666);
225
+ transition: all 0.15s ease;
226
+ }
227
+
228
+ ::slotted([role="tab"]:hover) {
229
+ color: var(--compa11y-tab-hover-color, #333);
230
+ }
231
+
232
+ ::slotted([role="tab"][aria-selected="true"]) {
233
+ color: var(--compa11y-tab-active-color, #0066cc);
234
+ border-bottom-color: currentColor;
235
+ }
236
+
237
+ ::slotted([role="tab"][aria-disabled="true"]) {
238
+ opacity: 0.5;
239
+ cursor: not-allowed;
240
+ }
241
+
242
+ ::slotted([role="tabpanel"]) {
243
+ padding: var(--compa11y-tabpanel-padding, 1rem 0);
244
+ }
245
+
246
+ ::slotted([role="tabpanel"][hidden]) {
247
+ display: none;
248
+ }
249
+ `, N = `
250
+ ${c}
251
+
252
+ :host {
253
+ display: inline-block;
254
+ position: relative;
255
+ width: var(--compa11y-combobox-width, 250px);
256
+ }
257
+
258
+ .combobox-wrapper {
259
+ position: relative;
260
+ }
261
+
262
+ .input-wrapper {
263
+ position: relative;
264
+ display: flex;
265
+ align-items: center;
266
+ }
267
+
268
+ input {
269
+ width: 100%;
270
+ padding: var(--compa11y-combobox-input-padding, 0.5rem 2rem 0.5rem 0.75rem);
271
+ border: var(--compa11y-combobox-border, 1px solid #ccc);
272
+ border-radius: var(--compa11y-combobox-radius, 4px);
273
+ font: inherit;
274
+ background: var(--compa11y-combobox-bg, white);
275
+ color: var(--compa11y-combobox-color, inherit);
276
+ }
277
+
278
+ input:focus {
279
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
280
+ outline-offset: -1px;
281
+ border-color: var(--compa11y-focus-color, #0066cc);
282
+ }
283
+
284
+ input::placeholder {
285
+ color: var(--compa11y-combobox-placeholder-color, #999);
286
+ }
287
+
288
+ input:disabled {
289
+ background: var(--compa11y-combobox-disabled-bg, #f5f5f5);
290
+ cursor: not-allowed;
291
+ opacity: 0.7;
292
+ }
293
+
294
+ .chevron {
295
+ position: absolute;
296
+ right: 0.5rem;
297
+ pointer-events: none;
298
+ font-size: 0.75rem;
299
+ color: var(--compa11y-combobox-chevron-color, #666);
300
+ transition: transform 0.15s ease;
301
+ }
302
+
303
+ :host([open]) .chevron {
304
+ transform: rotate(180deg);
305
+ }
306
+
307
+ .clear-button {
308
+ ${f}
309
+ position: absolute;
310
+ right: 1.5rem;
311
+ width: 1.25rem;
312
+ height: 1.25rem;
313
+ display: flex;
314
+ align-items: center;
315
+ justify-content: center;
316
+ border-radius: 50%;
317
+ font-size: 1rem;
318
+ color: var(--compa11y-combobox-clear-color, #666);
319
+ }
320
+
321
+ .clear-button:hover {
322
+ background: var(--compa11y-combobox-clear-hover-bg, rgba(0, 0, 0, 0.1));
323
+ }
324
+
325
+ .clear-button[hidden] {
326
+ display: none;
327
+ }
328
+
329
+ .listbox {
330
+ position: absolute;
331
+ top: 100%;
332
+ left: 0;
333
+ right: 0;
334
+ z-index: var(--compa11y-combobox-z-index, 1000);
335
+ max-height: var(--compa11y-combobox-max-height, 200px);
336
+ overflow-y: auto;
337
+ margin: 0;
338
+ padding: var(--compa11y-combobox-listbox-padding, 0.25rem 0);
339
+ background: var(--compa11y-combobox-listbox-bg, white);
340
+ border: var(--compa11y-combobox-listbox-border, 1px solid #e0e0e0);
341
+ border-radius: var(--compa11y-combobox-radius, 4px);
342
+ box-shadow: var(--compa11y-combobox-shadow, 0 4px 6px -1px rgba(0, 0, 0, 0.1));
343
+ list-style: none;
344
+ }
345
+
346
+ /* Flip chevron when listbox is positioned above */
347
+ :host([data-position="top"]) .chevron {
348
+ transform: rotate(180deg);
349
+ }
350
+
351
+ :host([data-position="top"][open]) .chevron {
352
+ transform: rotate(0deg);
353
+ }
354
+
355
+ .listbox[hidden] {
356
+ display: none;
357
+ }
358
+
359
+ .listbox li[role="option"] {
360
+ padding: var(--compa11y-combobox-option-padding, 0.5rem 0.75rem);
361
+ cursor: pointer;
362
+ transition: background 0.1s ease;
363
+ }
364
+
365
+ .listbox li[role="option"]:hover,
366
+ .listbox li[role="option"].highlighted {
367
+ background: var(--compa11y-combobox-option-hover-bg, #f5f5f5);
368
+ }
369
+
370
+ .listbox li[role="option"][aria-selected="true"] {
371
+ background: var(--compa11y-combobox-option-selected-bg, #e6f0ff);
372
+ font-weight: 500;
373
+ }
374
+
375
+ .listbox li[role="option"].disabled,
376
+ .listbox li[role="option"][aria-disabled="true"] {
377
+ opacity: 0.5;
378
+ cursor: not-allowed;
379
+ }
380
+
381
+ .empty-message {
382
+ padding: var(--compa11y-combobox-option-padding, 0.5rem 0.75rem);
383
+ color: var(--compa11y-combobox-empty-color, #666);
384
+ font-style: italic;
385
+ }
386
+
387
+ .options-source {
388
+ display: none;
389
+ }
390
+ `, U = `
391
+ ${c}
392
+
393
+ :host {
394
+ display: inline-block;
395
+ }
396
+
397
+ .switch-wrapper {
398
+ display: inline-flex;
399
+ align-items: center;
400
+ gap: var(--compa11y-switch-gap, 0.5rem);
401
+ }
402
+
403
+ /* Size variants */
404
+ .switch-wrapper.size-sm .switch-track {
405
+ width: var(--compa11y-switch-width-sm, 32px);
406
+ height: var(--compa11y-switch-height-sm, 18px);
407
+ }
408
+
409
+ .switch-wrapper.size-sm .switch-thumb {
410
+ width: var(--compa11y-switch-thumb-sm, 14px);
411
+ height: var(--compa11y-switch-thumb-sm, 14px);
412
+ }
413
+
414
+ .switch-wrapper.size-sm .switch-track.checked .switch-thumb {
415
+ transform: translateX(14px);
416
+ }
417
+
418
+ .switch-wrapper.size-md .switch-track {
419
+ width: var(--compa11y-switch-width-md, 44px);
420
+ height: var(--compa11y-switch-height-md, 24px);
421
+ }
422
+
423
+ .switch-wrapper.size-md .switch-thumb {
424
+ width: var(--compa11y-switch-thumb-md, 20px);
425
+ height: var(--compa11y-switch-thumb-md, 20px);
426
+ }
427
+
428
+ .switch-wrapper.size-md .switch-track.checked .switch-thumb {
429
+ transform: translateX(20px);
430
+ }
431
+
432
+ .switch-wrapper.size-lg .switch-track {
433
+ width: var(--compa11y-switch-width-lg, 56px);
434
+ height: var(--compa11y-switch-height-lg, 30px);
435
+ }
436
+
437
+ .switch-wrapper.size-lg .switch-thumb {
438
+ width: var(--compa11y-switch-thumb-lg, 26px);
439
+ height: var(--compa11y-switch-thumb-lg, 26px);
440
+ }
441
+
442
+ .switch-wrapper.size-lg .switch-track.checked .switch-thumb {
443
+ transform: translateX(26px);
444
+ }
445
+
446
+ .switch-track {
447
+ position: relative;
448
+ display: inline-flex;
449
+ align-items: center;
450
+ flex-shrink: 0;
451
+ padding: 2px;
452
+ border: none;
453
+ border-radius: var(--compa11y-switch-radius, 9999px);
454
+ background: var(--compa11y-switch-bg, #d1d5db);
455
+ cursor: pointer;
456
+ transition: background-color 0.2s ease;
457
+ outline: none;
458
+ }
459
+
460
+ .switch-track:focus-visible {
461
+ outline: 2px solid var(--compa11y-focus-color, #0066cc);
462
+ outline-offset: 2px;
463
+ }
464
+
465
+ .switch-track.checked {
466
+ background: var(--compa11y-switch-checked-bg, #0066cc);
467
+ }
468
+
469
+ .switch-track:disabled {
470
+ opacity: 0.5;
471
+ cursor: not-allowed;
472
+ }
473
+
474
+ .switch-thumb {
475
+ position: absolute;
476
+ left: 2px;
477
+ background: var(--compa11y-switch-thumb-bg, white);
478
+ border-radius: 50%;
479
+ box-shadow: var(--compa11y-switch-thumb-shadow, 0 1px 3px rgba(0, 0, 0, 0.2));
480
+ transition: transform 0.2s ease;
481
+ pointer-events: none;
482
+ }
483
+
484
+ .switch-label {
485
+ user-select: none;
486
+ cursor: pointer;
487
+ color: var(--compa11y-switch-label-color, inherit);
488
+ }
489
+
490
+ .switch-label.disabled {
491
+ opacity: 0.5;
492
+ cursor: not-allowed;
493
+ }
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
+ };
524
+ }
525
+ static get observedAttributes() {
526
+ return ["open", "trigger", "close-on-outside-click", "close-on-escape"];
527
+ }
528
+ get open() {
529
+ return this._open;
530
+ }
531
+ set open(t) {
532
+ const e = this._open;
533
+ this._open = t, t !== e && (t ? this.showDialog() : this.hideDialog()), this.toggleAttribute("open", t);
534
+ }
535
+ setupAccessibility() {
536
+ }
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");
564
+ }
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);
581
+ }
582
+ cleanupEventListeners() {
583
+ var t;
584
+ (t = this._triggerElement) == null || t.removeEventListener("click", this.handleTriggerClick), this.removeEventListener("keydown", this.handleKeyDown);
585
+ }
586
+ onAttributeChange(t, e, i) {
587
+ t === "open" && (this.open = i !== null);
588
+ }
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;
599
+ }
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");
605
+ }
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");
609
+ }
610
+ /**
611
+ * Programmatic open
612
+ */
613
+ show() {
614
+ this.open = !0;
615
+ }
616
+ /**
617
+ * Programmatic close
618
+ */
619
+ close() {
620
+ this.open = !1;
621
+ }
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
+ };
696
+ }
697
+ static get observedAttributes() {
698
+ return ["open"];
699
+ }
700
+ get open() {
701
+ return this._open;
702
+ }
703
+ set open(t) {
704
+ const e = this._open;
705
+ this._open = t, t !== e && this.updateMenuVisibility(), this.toggleAttribute("open", t);
706
+ }
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"));
710
+ }
711
+ 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
+ >
724
+ <slot></slot>
725
+ </div>
726
+ `;
727
+ }
728
+ 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();
739
+ }
740
+ cleanupEventListeners() {
741
+ document.removeEventListener("mousedown", this.handleOutsideClick);
742
+ }
743
+ onAttributeChange(t, e, i) {
744
+ t === "open" && (this.open = i !== null);
745
+ }
746
+ highlightItem(t, e = !0) {
747
+ var s;
748
+ if (this._highlightedIndex >= 0) {
749
+ const o = this._menuItems[this._highlightedIndex];
750
+ o == null || o.removeAttribute("data-highlighted");
751
+ }
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);
758
+ }
759
+ }
760
+ selectItem(t) {
761
+ const e = this._menuItems[t];
762
+ e && (this.emit("a11y-menu-select", { item: e, index: t }), e.click()), this.close();
763
+ }
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"));
770
+ }
771
+ /**
772
+ * Show the menu
773
+ */
774
+ show() {
775
+ this.open = !0;
776
+ }
777
+ /**
778
+ * Hide the menu
779
+ */
780
+ close() {
781
+ this.open = !1;
782
+ }
783
+ /**
784
+ * Toggle the menu
785
+ */
786
+ toggle() {
787
+ this.open = !this._open;
788
+ }
789
+ }
790
+ d("a11y-menu", _);
791
+ class x extends h {
792
+ 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;
828
+ }
829
+ (l = this._tabs[a]) == null || l.focus(), this.activationMode === "automatic" && this.selectTab(a);
830
+ };
831
+ }
832
+ static get observedAttributes() {
833
+ return ["orientation", "activation-mode", "selected-index"];
834
+ }
835
+ get selectedIndex() {
836
+ return this._selectedIndex;
837
+ }
838
+ set selectedIndex(t) {
839
+ t >= 0 && t < this._tabs.length && (this._selectedIndex = t, this.updateSelection());
840
+ }
841
+ get orientation() {
842
+ return this.getAttribute("orientation") || "horizontal";
843
+ }
844
+ get activationMode() {
845
+ return this.getAttribute("activation-mode") || "automatic";
846
+ }
847
+ setupAccessibility() {
848
+ this.updateTabsAndPanels();
849
+ }
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
+ `;
862
+ }
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);
868
+ }
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
+ }
887
+ }
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
+ });
895
+ }
896
+ /**
897
+ * Select a tab by index
898
+ */
899
+ select(t) {
900
+ this.selectTab(t);
901
+ }
902
+ /**
903
+ * Select next tab
904
+ */
905
+ next() {
906
+ this.selectTab((this._selectedIndex + 1) % this._tabs.length);
907
+ }
908
+ /**
909
+ * Select previous tab
910
+ */
911
+ previous() {
912
+ this.selectTab(
913
+ (this._selectedIndex - 1 + this._tabs.length) % this._tabs.length
914
+ );
915
+ }
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());
966
+ break;
967
+ case "End":
968
+ this._open && (t.preventDefault(), this._highlightedIndex = this._filteredOptions.length - 1, this.updateHighlight());
969
+ break;
970
+ case "Tab":
971
+ this._open && (this.open = !1, this._highlightedIndex = -1);
972
+ break;
973
+ }
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);
985
+ };
986
+ }
987
+ static get observedAttributes() {
988
+ return ["open", "value", "placeholder", "disabled", "clearable"];
989
+ }
990
+ get open() {
991
+ return this._open;
992
+ }
993
+ set open(t) {
994
+ const e = this._open;
995
+ this._open = t, t !== e && this.updateListboxVisibility(), this.toggleAttribute("open", t);
996
+ }
997
+ get value() {
998
+ return this._selectedValue;
999
+ }
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 || "");
1004
+ }
1005
+ setupAccessibility() {
1006
+ }
1007
+ 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>
1048
+ <slot></slot>
1049
+ </div>
1050
+ `, this._inputElement = t.querySelector("input"), this._listboxElement = t.querySelector(".listbox");
1051
+ }
1052
+ 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();
1059
+ }
1060
+ 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")));
1107
+ }
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"));
1116
+ }
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);
1123
+ }
1124
+ /**
1125
+ * Programmatic open
1126
+ */
1127
+ show() {
1128
+ this.open = !0;
1129
+ }
1130
+ /**
1131
+ * Programmatic close
1132
+ */
1133
+ close() {
1134
+ this.open = !1;
1135
+ }
1136
+ /**
1137
+ * Clear the selection
1138
+ */
1139
+ clear() {
1140
+ this.handleClear();
1141
+ }
1142
+ }
1143
+ d("a11y-combobox", v);
1144
+ class w extends h {
1145
+ 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());
1153
+ };
1154
+ }
1155
+ static get observedAttributes() {
1156
+ return ["checked", "disabled", "label", "size", "aria-label"];
1157
+ }
1158
+ /**
1159
+ * Get/set the checked state
1160
+ */
1161
+ get checked() {
1162
+ return this._checked;
1163
+ }
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 }));
1167
+ }
1168
+ /**
1169
+ * Get/set the disabled state
1170
+ */
1171
+ get disabled() {
1172
+ return this.hasAttribute("disabled");
1173
+ }
1174
+ set disabled(t) {
1175
+ this.toggleAttribute("disabled", t), this.updateDisabledState();
1176
+ }
1177
+ /**
1178
+ * Get/set the visible label
1179
+ */
1180
+ get label() {
1181
+ return this.getAttribute("label") || "";
1182
+ }
1183
+ set label(t) {
1184
+ t ? this.setAttribute("label", t) : this.removeAttribute("label");
1185
+ }
1186
+ /**
1187
+ * Get/set the size variant
1188
+ */
1189
+ get size() {
1190
+ const t = this.getAttribute("size");
1191
+ return t === "sm" || t === "lg" ? t : "md";
1192
+ }
1193
+ set size(t) {
1194
+ this.setAttribute("size", t);
1195
+ }
1196
+ 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>`
1201
+ );
1202
+ }
1203
+ 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>` : ""}
1222
+ </div>
1223
+ `, this._button = t.querySelector("button"), this._label = t.querySelector("label");
1224
+ }
1225
+ 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);
1228
+ }
1229
+ 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);
1232
+ }
1233
+ onAttributeChange(t, e, i) {
1234
+ switch (t) {
1235
+ case "checked":
1236
+ this._checked = i !== null, this.updateVisualState();
1237
+ break;
1238
+ case "disabled":
1239
+ this.updateDisabledState();
1240
+ break;
1241
+ case "label":
1242
+ case "aria-label":
1243
+ this.shadowRoot && (this.shadowRoot.innerHTML = "", this.render(), this.setupEventListeners());
1244
+ break;
1245
+ case "size":
1246
+ this.updateSizeClass();
1247
+ break;
1248
+ }
1249
+ }
1250
+ /**
1251
+ * Update the visual state (checked class and aria-checked)
1252
+ */
1253
+ updateVisualState() {
1254
+ this._button && (this._button.setAttribute("aria-checked", String(this._checked)), this._button.classList.toggle("checked", this._checked));
1255
+ }
1256
+ /**
1257
+ * Update the disabled state
1258
+ */
1259
+ 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);
1261
+ }
1262
+ /**
1263
+ * Update the size class
1264
+ */
1265
+ 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}`));
1269
+ }
1270
+ /**
1271
+ * Public method to toggle the switch programmatically
1272
+ */
1273
+ toggle() {
1274
+ 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"}`);
1278
+ }
1279
+ /**
1280
+ * Public method to open/close programmatically
1281
+ */
1282
+ setChecked(t) {
1283
+ this.checked = t;
1284
+ }
1285
+ }
1286
+ d("a11y-switch", w);
1287
+ if (typeof window < "u") {
1288
+ const n = () => {
1289
+ b(), p();
1290
+ };
1291
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", n) : n(), window.compa11y = {
1292
+ // Components (classes)
1293
+ A11yDialog: y,
1294
+ A11yMenu: _,
1295
+ A11yTabs: x,
1296
+ A11yCombobox: v,
1297
+ A11ySwitch: w,
1298
+ // Announcer utilities
1299
+ initAnnouncer: b,
1300
+ announce: r,
1301
+ announcePolite: g,
1302
+ announceAssertive: V,
1303
+ announceStatus: H,
1304
+ announceError: R,
1305
+ // Focus utilities
1306
+ initFocusVisible: p,
1307
+ createFocusTrap: M,
1308
+ createFocusScope: q,
1309
+ createRovingTabindex: z,
1310
+ // Keyboard utilities
1311
+ createKeyboardManager: O,
1312
+ KeyboardPatterns: D,
1313
+ createTypeAhead: T,
1314
+ // ARIA utilities
1315
+ aria: $,
1316
+ buildAriaProps: C,
1317
+ hasAccessibleName: S,
1318
+ // Platform detection
1319
+ isBrowser: L,
1320
+ prefersReducedMotion: I,
1321
+ prefersHighContrast: A,
1322
+ prefersDarkMode: k
1323
+ };
1324
+ }
1325
+ 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
1351
+ };
1352
+ //# sourceMappingURL=compa11y.js.map