aria-ease 3.0.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +6 -6
  2. package/bin/cli.cjs +90 -22
  3. package/bin/cli.js +1 -1
  4. package/bin/{contractTestRunnerPlaywright-TLQZGKW7.js → contractTestRunnerPlaywright-EZLNNJV5.js} +43 -10
  5. package/bin/{test-Q7W3WQEA.js → test-45KMD4F4.js} +47 -12
  6. package/dist/{contractTestRunnerPlaywright-7U2O33SR.js → contractTestRunnerPlaywright-UQQI5MYS.js} +43 -10
  7. package/dist/index.cjs +663 -38
  8. package/dist/index.d.cts +88 -6
  9. package/dist/index.d.ts +88 -6
  10. package/dist/index.js +616 -28
  11. package/dist/src/{Types.d-uG0Hm1yK.d.ts → Types.d-BrHSyS03.d.cts} +17 -0
  12. package/dist/src/{Types.d-uG0Hm1yK.d.cts → Types.d-BrHSyS03.d.ts} +17 -0
  13. package/dist/src/accordion/index.cjs +159 -0
  14. package/dist/src/accordion/index.d.cts +19 -2
  15. package/dist/src/accordion/index.d.ts +19 -2
  16. package/dist/src/accordion/index.js +159 -1
  17. package/dist/src/block/index.cjs +1 -1
  18. package/dist/src/block/index.d.cts +6 -2
  19. package/dist/src/block/index.d.ts +6 -2
  20. package/dist/src/block/index.js +1 -1
  21. package/dist/src/checkbox/index.cjs +129 -0
  22. package/dist/src/checkbox/index.d.cts +15 -2
  23. package/dist/src/checkbox/index.d.ts +15 -2
  24. package/dist/src/checkbox/index.js +129 -1
  25. package/dist/src/combobox/index.d.cts +1 -1
  26. package/dist/src/combobox/index.d.ts +1 -1
  27. package/dist/src/menu/index.cjs +13 -15
  28. package/dist/src/menu/index.d.cts +1 -1
  29. package/dist/src/menu/index.d.ts +1 -1
  30. package/dist/src/menu/index.js +13 -15
  31. package/dist/src/radio/index.cjs +122 -0
  32. package/dist/src/radio/index.d.cts +17 -2
  33. package/dist/src/radio/index.d.ts +17 -2
  34. package/dist/src/radio/index.js +122 -1
  35. package/dist/src/toggle/index.cjs +145 -0
  36. package/dist/src/toggle/index.d.cts +17 -2
  37. package/dist/src/toggle/index.d.ts +17 -2
  38. package/dist/src/toggle/index.js +145 -1
  39. package/dist/src/utils/test/{contractTestRunnerPlaywright-7U2O33SR.js → contractTestRunnerPlaywright-UQQI5MYS.js} +43 -10
  40. package/dist/src/utils/test/index.cjs +90 -22
  41. package/dist/src/utils/test/index.d.cts +5 -4
  42. package/dist/src/utils/test/index.d.ts +5 -4
  43. package/dist/src/utils/test/index.js +47 -12
  44. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9208,6 +9208,164 @@ function updateAccordionTriggerAriaAttributes(accordionId, accordionTriggersClas
9208
9208
  });
9209
9209
  }
9210
9210
 
9211
+ // src/accordion/src/makeAccordionAccessible/makeAccordionAccessible.ts
9212
+ function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultiple = false }) {
9213
+ const accordionContainer = document.querySelector(`#${accordionId}`);
9214
+ if (!accordionContainer) {
9215
+ console.error(`[aria-ease] Element with id="${accordionId}" not found. Make sure the accordion container exists before calling makeAccordionAccessible.`);
9216
+ return { cleanup: () => {
9217
+ } };
9218
+ }
9219
+ const triggers = Array.from(accordionContainer.querySelectorAll(`.${triggersClass}`));
9220
+ if (triggers.length === 0) {
9221
+ console.error(`[aria-ease] No elements with class="${triggersClass}" found. Make sure accordion triggers exist before calling makeAccordionAccessible.`);
9222
+ return { cleanup: () => {
9223
+ } };
9224
+ }
9225
+ const panels = Array.from(accordionContainer.querySelectorAll(`.${panelsClass}`));
9226
+ if (panels.length === 0) {
9227
+ console.error(`[aria-ease] No elements with class="${panelsClass}" found. Make sure accordion panels exist before calling makeAccordionAccessible.`);
9228
+ return { cleanup: () => {
9229
+ } };
9230
+ }
9231
+ if (triggers.length !== panels.length) {
9232
+ console.error(`[aria-ease] Accordion trigger/panel mismatch: found ${triggers.length} triggers but ${panels.length} panels.`);
9233
+ return { cleanup: () => {
9234
+ } };
9235
+ }
9236
+ const handlerMap = /* @__PURE__ */ new WeakMap();
9237
+ const clickHandlerMap = /* @__PURE__ */ new WeakMap();
9238
+ function initialize() {
9239
+ triggers.forEach((trigger, index) => {
9240
+ const panel = panels[index];
9241
+ if (!trigger.id) {
9242
+ trigger.id = `${accordionId}-trigger-${index}`;
9243
+ }
9244
+ if (!panel.id) {
9245
+ panel.id = `${accordionId}-panel-${index}`;
9246
+ }
9247
+ trigger.setAttribute("aria-controls", panel.id);
9248
+ trigger.setAttribute("aria-expanded", "false");
9249
+ panel.setAttribute("role", "region");
9250
+ panel.setAttribute("aria-labelledby", trigger.id);
9251
+ panel.style.display = "none";
9252
+ });
9253
+ }
9254
+ function expandItem(index) {
9255
+ if (index < 0 || index >= triggers.length) {
9256
+ console.error(`[aria-ease] Invalid accordion index: ${index}`);
9257
+ return;
9258
+ }
9259
+ const trigger = triggers[index];
9260
+ const panel = panels[index];
9261
+ trigger.setAttribute("aria-expanded", "true");
9262
+ panel.style.display = "block";
9263
+ }
9264
+ function collapseItem(index) {
9265
+ if (index < 0 || index >= triggers.length) {
9266
+ console.error(`[aria-ease] Invalid accordion index: ${index}`);
9267
+ return;
9268
+ }
9269
+ const trigger = triggers[index];
9270
+ const panel = panels[index];
9271
+ trigger.setAttribute("aria-expanded", "false");
9272
+ panel.style.display = "none";
9273
+ }
9274
+ function toggleItem(index) {
9275
+ const trigger = triggers[index];
9276
+ const isExpanded = trigger.getAttribute("aria-expanded") === "true";
9277
+ if (isExpanded) {
9278
+ collapseItem(index);
9279
+ } else {
9280
+ if (!allowMultiple) {
9281
+ triggers.forEach((_, i) => {
9282
+ if (i !== index) {
9283
+ collapseItem(i);
9284
+ }
9285
+ });
9286
+ }
9287
+ expandItem(index);
9288
+ }
9289
+ }
9290
+ function handleTriggerClick(index) {
9291
+ return () => {
9292
+ toggleItem(index);
9293
+ };
9294
+ }
9295
+ function handleTriggerKeydown(index) {
9296
+ return (event) => {
9297
+ const { key } = event;
9298
+ switch (key) {
9299
+ case "Enter":
9300
+ case " ":
9301
+ event.preventDefault();
9302
+ toggleItem(index);
9303
+ break;
9304
+ case "ArrowDown":
9305
+ event.preventDefault();
9306
+ {
9307
+ const nextIndex = (index + 1) % triggers.length;
9308
+ triggers[nextIndex].focus();
9309
+ }
9310
+ break;
9311
+ case "ArrowUp":
9312
+ event.preventDefault();
9313
+ {
9314
+ const prevIndex = (index - 1 + triggers.length) % triggers.length;
9315
+ triggers[prevIndex].focus();
9316
+ }
9317
+ break;
9318
+ case "Home":
9319
+ event.preventDefault();
9320
+ triggers[0].focus();
9321
+ break;
9322
+ case "End":
9323
+ event.preventDefault();
9324
+ triggers[triggers.length - 1].focus();
9325
+ break;
9326
+ }
9327
+ };
9328
+ }
9329
+ function addListeners() {
9330
+ triggers.forEach((trigger, index) => {
9331
+ const clickHandler = handleTriggerClick(index);
9332
+ const keydownHandler = handleTriggerKeydown(index);
9333
+ trigger.addEventListener("click", clickHandler);
9334
+ trigger.addEventListener("keydown", keydownHandler);
9335
+ handlerMap.set(trigger, keydownHandler);
9336
+ clickHandlerMap.set(trigger, clickHandler);
9337
+ });
9338
+ }
9339
+ function removeListeners() {
9340
+ triggers.forEach((trigger) => {
9341
+ const keydownHandler = handlerMap.get(trigger);
9342
+ const clickHandler = clickHandlerMap.get(trigger);
9343
+ if (keydownHandler) {
9344
+ trigger.removeEventListener("keydown", keydownHandler);
9345
+ handlerMap.delete(trigger);
9346
+ }
9347
+ if (clickHandler) {
9348
+ trigger.removeEventListener("click", clickHandler);
9349
+ clickHandlerMap.delete(trigger);
9350
+ }
9351
+ });
9352
+ }
9353
+ function cleanup() {
9354
+ removeListeners();
9355
+ triggers.forEach((_, index) => {
9356
+ collapseItem(index);
9357
+ });
9358
+ }
9359
+ initialize();
9360
+ addListeners();
9361
+ return {
9362
+ expandItem,
9363
+ collapseItem,
9364
+ toggleItem,
9365
+ cleanup
9366
+ };
9367
+ }
9368
+
9211
9369
  // src/utils/handleKeyPress/handleKeyPress.ts
9212
9370
  function isTextInput(el) {
9213
9371
  if (el.tagName !== "INPUT") return false;
@@ -9331,7 +9489,7 @@ function handleKeyPress(event, elementItems, elementItemIndex, menuElementDiv, t
9331
9489
  }
9332
9490
 
9333
9491
  // src/block/src/makeBlockAccessible/makeBlockAccessible.ts
9334
- function makeBlockAccessible(blockId, blockItemsClass) {
9492
+ function makeBlockAccessible({ blockId, blockItemsClass }) {
9335
9493
  const blockDiv = document.querySelector(`#${blockId}`);
9336
9494
  if (!blockDiv) {
9337
9495
  console.error(`[aria-ease] Element with id="${blockId}" not found. Make sure the block element exists before calling makeBlockAccessible.`);
@@ -9410,6 +9568,134 @@ function updateCheckboxAriaAttributes(checkboxId, checkboxesClass, checkboxState
9410
9568
  });
9411
9569
  }
9412
9570
 
9571
+ // src/checkbox/src/makeCheckboxAccessible/makeCheckboxAccessible.ts
9572
+ function makeCheckboxAccessible({ checkboxGroupId, checkboxesClass }) {
9573
+ const checkboxGroup = document.querySelector(`#${checkboxGroupId}`);
9574
+ if (!checkboxGroup) {
9575
+ console.error(`[aria-ease] Element with id="${checkboxGroupId}" not found. Make sure the checkbox group container exists before calling makeCheckboxAccessible.`);
9576
+ return { cleanup: () => {
9577
+ } };
9578
+ }
9579
+ const checkboxes = Array.from(checkboxGroup.querySelectorAll(`.${checkboxesClass}`));
9580
+ if (checkboxes.length === 0) {
9581
+ console.error(`[aria-ease] No elements with class="${checkboxesClass}" found. Make sure checkboxes exist before calling makeCheckboxAccessible.`);
9582
+ return { cleanup: () => {
9583
+ } };
9584
+ }
9585
+ const handlerMap = /* @__PURE__ */ new WeakMap();
9586
+ const clickHandlerMap = /* @__PURE__ */ new WeakMap();
9587
+ function initialize() {
9588
+ if (!checkboxGroup.getAttribute("role")) {
9589
+ checkboxGroup.setAttribute("role", "group");
9590
+ }
9591
+ checkboxes.forEach((checkbox) => {
9592
+ checkbox.setAttribute("role", "checkbox");
9593
+ if (!checkbox.hasAttribute("aria-checked")) {
9594
+ checkbox.setAttribute("aria-checked", "false");
9595
+ }
9596
+ if (!checkbox.hasAttribute("tabindex")) {
9597
+ checkbox.setAttribute("tabindex", "0");
9598
+ }
9599
+ });
9600
+ }
9601
+ function toggleCheckbox(index) {
9602
+ if (index < 0 || index >= checkboxes.length) {
9603
+ console.error(`[aria-ease] Invalid checkbox index: ${index}`);
9604
+ return;
9605
+ }
9606
+ const checkbox = checkboxes[index];
9607
+ const isChecked = checkbox.getAttribute("aria-checked") === "true";
9608
+ checkbox.setAttribute("aria-checked", isChecked ? "false" : "true");
9609
+ }
9610
+ function setCheckboxState(index, checked) {
9611
+ if (index < 0 || index >= checkboxes.length) {
9612
+ console.error(`[aria-ease] Invalid checkbox index: ${index}`);
9613
+ return;
9614
+ }
9615
+ checkboxes[index].setAttribute("aria-checked", checked ? "true" : "false");
9616
+ }
9617
+ function handleCheckboxClick(index) {
9618
+ return () => {
9619
+ toggleCheckbox(index);
9620
+ };
9621
+ }
9622
+ function handleCheckboxKeydown(index) {
9623
+ return (event) => {
9624
+ const { key } = event;
9625
+ switch (key) {
9626
+ case " ":
9627
+ event.preventDefault();
9628
+ toggleCheckbox(index);
9629
+ break;
9630
+ case "ArrowDown":
9631
+ event.preventDefault();
9632
+ {
9633
+ const nextIndex = (index + 1) % checkboxes.length;
9634
+ checkboxes[nextIndex].focus();
9635
+ }
9636
+ break;
9637
+ case "ArrowUp":
9638
+ event.preventDefault();
9639
+ {
9640
+ const prevIndex = (index - 1 + checkboxes.length) % checkboxes.length;
9641
+ checkboxes[prevIndex].focus();
9642
+ }
9643
+ break;
9644
+ case "Home":
9645
+ event.preventDefault();
9646
+ checkboxes[0].focus();
9647
+ break;
9648
+ case "End":
9649
+ event.preventDefault();
9650
+ checkboxes[checkboxes.length - 1].focus();
9651
+ break;
9652
+ }
9653
+ };
9654
+ }
9655
+ function addListeners() {
9656
+ checkboxes.forEach((checkbox, index) => {
9657
+ const clickHandler = handleCheckboxClick(index);
9658
+ const keydownHandler = handleCheckboxKeydown(index);
9659
+ checkbox.addEventListener("click", clickHandler);
9660
+ checkbox.addEventListener("keydown", keydownHandler);
9661
+ handlerMap.set(checkbox, keydownHandler);
9662
+ clickHandlerMap.set(checkbox, clickHandler);
9663
+ });
9664
+ }
9665
+ function removeListeners() {
9666
+ checkboxes.forEach((checkbox) => {
9667
+ const keydownHandler = handlerMap.get(checkbox);
9668
+ const clickHandler = clickHandlerMap.get(checkbox);
9669
+ if (keydownHandler) {
9670
+ checkbox.removeEventListener("keydown", keydownHandler);
9671
+ handlerMap.delete(checkbox);
9672
+ }
9673
+ if (clickHandler) {
9674
+ checkbox.removeEventListener("click", clickHandler);
9675
+ clickHandlerMap.delete(checkbox);
9676
+ }
9677
+ });
9678
+ }
9679
+ function cleanup() {
9680
+ removeListeners();
9681
+ }
9682
+ function getCheckedStates() {
9683
+ return checkboxes.map((checkbox) => checkbox.getAttribute("aria-checked") === "true");
9684
+ }
9685
+ function getCheckedIndices() {
9686
+ return checkboxes.map((checkbox, index) => checkbox.getAttribute("aria-checked") === "true" ? index : -1).filter((index) => index !== -1);
9687
+ }
9688
+ initialize();
9689
+ addListeners();
9690
+ return {
9691
+ toggleCheckbox,
9692
+ setCheckboxState,
9693
+ getCheckedStates,
9694
+ getCheckedIndices,
9695
+ cleanup
9696
+ };
9697
+ }
9698
+
9413
9699
  // src/menu/src/makeMenuAccessible/makeMenuAccessible.ts
9414
9700
  function makeMenuAccessible({ menuId, menuItemsClass, triggerId }) {
9415
9701
  const menuDiv = document.querySelector(`#${menuId}`);
@@ -9440,7 +9726,6 @@ function makeMenuAccessible({ menuId, menuItemsClass, triggerId }) {
9440
9726
  triggerButton.setAttribute("aria-expanded", "false");
9441
9727
  menuDiv.setAttribute("role", "menu");
9442
9728
  menuDiv.setAttribute("aria-labelledby", triggerId);
9443
- menuDiv.style.display = "none";
9444
9729
  const handlerMap = /* @__PURE__ */ new WeakMap();
9445
9730
  const submenuInstances = /* @__PURE__ */ new Map();
9446
9731
  let cachedItems = null;
@@ -9576,41 +9861,40 @@ function makeMenuAccessible({ menuId, menuItemsClass, triggerId }) {
9576
9861
  item.setAttribute("role", "menuitem");
9577
9862
  });
9578
9863
  }
9864
+ intializeMenuItems();
9579
9865
  function handleTriggerKeydown(event) {
9580
- const key = event.key;
9581
- if (key === "Enter" || key === " ") {
9866
+ if (event.key === "Enter" || event.key === " ") {
9582
9867
  event.preventDefault();
9583
- const isExpanded = triggerButton.getAttribute("aria-expanded") === "true";
9584
- if (isExpanded) {
9868
+ const isOpen = menuDiv.style.display !== "none";
9869
+ if (isOpen) {
9585
9870
  closeMenu();
9586
9871
  } else {
9587
9872
  openMenu();
9588
9873
  }
9589
9874
  }
9590
9875
  }
9591
- let isTransitioning = false;
9592
9876
  function handleTriggerClick() {
9593
- if (isTransitioning) return;
9594
- const isExpanded = triggerButton.getAttribute("aria-expanded") === "true";
9595
- isTransitioning = true;
9596
- if (isExpanded) {
9877
+ const isOpen = menuDiv.style.display !== "none";
9878
+ if (isOpen) {
9597
9879
  closeMenu();
9598
9880
  } else {
9599
9881
  openMenu();
9600
9882
  }
9601
- setTimeout(() => {
9602
- isTransitioning = false;
9603
- }, 100);
9604
9883
  }
9605
- intializeMenuItems();
9884
+ function handleClickOutside(event) {
9885
+ if (menuDiv && triggerButton && !menuDiv.contains(event.target) && !triggerButton.contains(event.target) && getComputedStyle(menuDiv).display !== "none" && triggerButton.getAttribute("aria-expanded") === "true") {
9886
+ closeMenu();
9887
+ }
9888
+ }
9606
9889
  triggerButton.addEventListener("keydown", handleTriggerKeydown);
9607
9890
  triggerButton.addEventListener("click", handleTriggerClick);
9891
+ document.addEventListener("click", handleClickOutside);
9608
9892
  triggerButton.setAttribute("data-menu-initialized", "true");
9609
9893
  function cleanup() {
9610
9894
  removeListeners();
9611
9895
  triggerButton.removeEventListener("keydown", handleTriggerKeydown);
9612
9896
  triggerButton.removeEventListener("click", handleTriggerClick);
9613
- triggerButton.removeAttribute("data-menu-initialized");
9897
+ document.removeEventListener("click", handleClickOutside);
9614
9898
  menuDiv.style.display = "none";
9615
9899
  setAria(false);
9616
9900
  submenuInstances.forEach((instance) => instance.cleanup());
@@ -9653,6 +9937,127 @@ function updateRadioAriaAttributes(radioId, radiosClass, radioStates, currentPre
9653
9937
  });
9654
9938
  }
9655
9939
 
9940
+ // src/radio/src/makeRadioAccessible/makeRadioAccessible.ts
9941
+ function makeRadioAccessible({ radioGroupId, radiosClass, defaultSelectedIndex = 0 }) {
9942
+ const radioGroup = document.querySelector(`#${radioGroupId}`);
9943
+ if (!radioGroup) {
9944
+ console.error(`[aria-ease] Element with id="${radioGroupId}" not found. Make sure the radio group container exists before calling makeRadioAccessible.`);
9945
+ return { cleanup: () => {
9946
+ } };
9947
+ }
9948
+ const radios = Array.from(radioGroup.querySelectorAll(`.${radiosClass}`));
9949
+ if (radios.length === 0) {
9950
+ console.error(`[aria-ease] No elements with class="${radiosClass}" found. Make sure radio buttons exist before calling makeRadioAccessible.`);
9951
+ return { cleanup: () => {
9952
+ } };
9953
+ }
9954
+ const handlerMap = /* @__PURE__ */ new WeakMap();
9955
+ const clickHandlerMap = /* @__PURE__ */ new WeakMap();
9956
+ let currentSelectedIndex = defaultSelectedIndex;
9957
+ function initialize() {
9958
+ if (!radioGroup.getAttribute("role")) {
9959
+ radioGroup.setAttribute("role", "radiogroup");
9960
+ }
9961
+ radios.forEach((radio, index) => {
9962
+ radio.setAttribute("role", "radio");
9963
+ radio.setAttribute("tabindex", index === currentSelectedIndex ? "0" : "-1");
9964
+ if (index === currentSelectedIndex) {
9965
+ radio.setAttribute("aria-checked", "true");
9966
+ } else {
9967
+ radio.setAttribute("aria-checked", "false");
9968
+ }
9969
+ });
9970
+ }
9971
+ function selectRadio(index) {
9972
+ if (index < 0 || index >= radios.length) {
9973
+ console.error(`[aria-ease] Invalid radio index: ${index}`);
9974
+ return;
9975
+ }
9976
+ if (currentSelectedIndex >= 0 && currentSelectedIndex < radios.length) {
9977
+ radios[currentSelectedIndex].setAttribute("aria-checked", "false");
9978
+ radios[currentSelectedIndex].setAttribute("tabindex", "-1");
9979
+ }
9980
+ radios[index].setAttribute("aria-checked", "true");
9981
+ radios[index].setAttribute("tabindex", "0");
9982
+ radios[index].focus();
9983
+ currentSelectedIndex = index;
9984
+ }
9985
+ function handleRadioClick(index) {
9986
+ return () => {
9987
+ selectRadio(index);
9988
+ };
9989
+ }
9990
+ function handleRadioKeydown(index) {
9991
+ return (event) => {
9992
+ const { key } = event;
9993
+ let nextIndex = index;
9994
+ switch (key) {
9995
+ case "ArrowDown":
9996
+ case "ArrowRight":
9997
+ event.preventDefault();
9998
+ nextIndex = (index + 1) % radios.length;
9999
+ selectRadio(nextIndex);
10000
+ break;
10001
+ case "ArrowUp":
10002
+ case "ArrowLeft":
10003
+ event.preventDefault();
10004
+ nextIndex = (index - 1 + radios.length) % radios.length;
10005
+ selectRadio(nextIndex);
10006
+ break;
10007
+ case " ":
10008
+ event.preventDefault();
10009
+ selectRadio(index);
10010
+ break;
10011
+ case "Home":
10012
+ event.preventDefault();
10013
+ selectRadio(0);
10014
+ break;
10015
+ case "End":
10016
+ event.preventDefault();
10017
+ selectRadio(radios.length - 1);
10018
+ break;
10019
+ }
10020
+ };
10021
+ }
10022
+ function addListeners() {
10023
+ radios.forEach((radio, index) => {
10024
+ const clickHandler = handleRadioClick(index);
10025
+ const keydownHandler = handleRadioKeydown(index);
10026
+ radio.addEventListener("click", clickHandler);
10027
+ radio.addEventListener("keydown", keydownHandler);
10028
+ handlerMap.set(radio, keydownHandler);
10029
+ clickHandlerMap.set(radio, clickHandler);
10030
+ });
10031
+ }
10032
+ function removeListeners() {
10033
+ radios.forEach((radio) => {
10034
+ const keydownHandler = handlerMap.get(radio);
10035
+ const clickHandler = clickHandlerMap.get(radio);
10036
+ if (keydownHandler) {
10037
+ radio.removeEventListener("keydown", keydownHandler);
10038
+ handlerMap.delete(radio);
10039
+ }
10040
+ if (clickHandler) {
10041
+ radio.removeEventListener("click", clickHandler);
10042
+ clickHandlerMap.delete(radio);
10043
+ }
10044
+ });
10045
+ }
10046
+ function cleanup() {
10047
+ removeListeners();
10048
+ }
10049
+ function getSelectedIndex() {
10050
+ return currentSelectedIndex;
10051
+ }
10052
+ initialize();
10053
+ addListeners();
10054
+ return {
10055
+ selectRadio,
10056
+ getSelectedIndex,
10057
+ cleanup
10058
+ };
10059
+ }
10060
+
9656
10061
  // src/toggle/src/updateToggleAriaAttribute/updateToggleAriaAttribute.ts
9657
10062
  function updateToggleAriaAttribute(toggleId, togglesClass, toggleStates, currentPressedToggleIndex) {
9658
10063
  const toggleDiv = document.querySelector(`#${toggleId}`);
@@ -9680,6 +10085,150 @@ function updateToggleAriaAttribute(toggleId, togglesClass, toggleStates, current
9680
10085
  });
9681
10086
  }
9682
10087
 
10088
+ // src/toggle/src/makeTogggleAccessible/makeToggleAccessible.ts
10089
+ function makeToggleAccessible({ toggleId, togglesClass, isSingleToggle = true }) {
10090
+ const toggleContainer = document.querySelector(`#${toggleId}`);
10091
+ if (!toggleContainer) {
10092
+ console.error(`[aria-ease] Element with id="${toggleId}" not found. Make sure the toggle element exists before calling makeToggleAccessible.`);
10093
+ return { cleanup: () => {
10094
+ } };
10095
+ }
10096
+ let toggles;
10097
+ if (isSingleToggle) {
10098
+ toggles = [toggleContainer];
10099
+ } else {
10100
+ if (!togglesClass) {
10101
+ console.error(`[aria-ease] togglesClass is required when isSingleToggle is false.`);
10102
+ return { cleanup: () => {
10103
+ } };
10104
+ }
10105
+ toggles = Array.from(toggleContainer.querySelectorAll(`.${togglesClass}`));
10106
+ if (toggles.length === 0) {
10107
+ console.error(`[aria-ease] No elements with class="${togglesClass}" found. Make sure toggle buttons exist before calling makeToggleAccessible.`);
10108
+ return { cleanup: () => {
10109
+ } };
10110
+ }
10111
+ }
10112
+ const handlerMap = /* @__PURE__ */ new WeakMap();
10113
+ const clickHandlerMap = /* @__PURE__ */ new WeakMap();
10114
+ function initialize() {
10115
+ toggles.forEach((toggle) => {
10116
+ if (toggle.tagName.toLowerCase() !== "button" && !toggle.getAttribute("role")) {
10117
+ toggle.setAttribute("role", "button");
10118
+ }
10119
+ if (!toggle.hasAttribute("aria-pressed")) {
10120
+ toggle.setAttribute("aria-pressed", "false");
10121
+ }
10122
+ if (!toggle.hasAttribute("tabindex")) {
10123
+ toggle.setAttribute("tabindex", "0");
10124
+ }
10125
+ });
10126
+ }
10127
+ function toggleButton(index) {
10128
+ if (index < 0 || index >= toggles.length) {
10129
+ console.error(`[aria-ease] Invalid toggle index: ${index}`);
10130
+ return;
10131
+ }
10132
+ const toggle = toggles[index];
10133
+ const isPressed = toggle.getAttribute("aria-pressed") === "true";
10134
+ toggle.setAttribute("aria-pressed", isPressed ? "false" : "true");
10135
+ }
10136
+ function setPressed(index, pressed) {
10137
+ if (index < 0 || index >= toggles.length) {
10138
+ console.error(`[aria-ease] Invalid toggle index: ${index}`);
10139
+ return;
10140
+ }
10141
+ toggles[index].setAttribute("aria-pressed", pressed ? "true" : "false");
10142
+ }
10143
+ function handleToggleClick(index) {
10144
+ return () => {
10145
+ toggleButton(index);
10146
+ };
10147
+ }
10148
+ function handleToggleKeydown(index) {
10149
+ return (event) => {
10150
+ const { key } = event;
10151
+ switch (key) {
10152
+ case "Enter":
10153
+ case " ":
10154
+ event.preventDefault();
10155
+ toggleButton(index);
10156
+ break;
10157
+ case "ArrowDown":
10158
+ case "ArrowRight":
10159
+ if (!isSingleToggle && toggles.length > 1) {
10160
+ event.preventDefault();
10161
+ const nextIndex = (index + 1) % toggles.length;
10162
+ toggles[nextIndex].focus();
10163
+ }
10164
+ break;
10165
+ case "ArrowUp":
10166
+ case "ArrowLeft":
10167
+ if (!isSingleToggle && toggles.length > 1) {
10168
+ event.preventDefault();
10169
+ const prevIndex = (index - 1 + toggles.length) % toggles.length;
10170
+ toggles[prevIndex].focus();
10171
+ }
10172
+ break;
10173
+ case "Home":
10174
+ if (!isSingleToggle && toggles.length > 1) {
10175
+ event.preventDefault();
10176
+ toggles[0].focus();
10177
+ }
10178
+ break;
10179
+ case "End":
10180
+ if (!isSingleToggle && toggles.length > 1) {
10181
+ event.preventDefault();
10182
+ toggles[toggles.length - 1].focus();
10183
+ }
10184
+ break;
10185
+ }
10186
+ };
10187
+ }
10188
+ function addListeners() {
10189
+ toggles.forEach((toggle, index) => {
10190
+ const clickHandler = handleToggleClick(index);
10191
+ const keydownHandler = handleToggleKeydown(index);
10192
+ toggle.addEventListener("click", clickHandler);
10193
+ toggle.addEventListener("keydown", keydownHandler);
10194
+ handlerMap.set(toggle, keydownHandler);
10195
+ clickHandlerMap.set(toggle, clickHandler);
10196
+ });
10197
+ }
10198
+ function removeListeners() {
10199
+ toggles.forEach((toggle) => {
10200
+ const keydownHandler = handlerMap.get(toggle);
10201
+ const clickHandler = clickHandlerMap.get(toggle);
10202
+ if (keydownHandler) {
10203
+ toggle.removeEventListener("keydown", keydownHandler);
10204
+ handlerMap.delete(toggle);
10205
+ }
10206
+ if (clickHandler) {
10207
+ toggle.removeEventListener("click", clickHandler);
10208
+ clickHandlerMap.delete(toggle);
10209
+ }
10210
+ });
10211
+ }
10212
+ function cleanup() {
10213
+ removeListeners();
10214
+ }
10215
+ function getPressedStates() {
10216
+ return toggles.map((toggle) => toggle.getAttribute("aria-pressed") === "true");
10217
+ }
10218
+ function getPressedIndices() {
10219
+ return toggles.map((toggle, index) => toggle.getAttribute("aria-pressed") === "true" ? index : -1).filter((index) => index !== -1);
10220
+ }
10221
+ initialize();
10222
+ addListeners();
10223
+ return {
10224
+ toggleButton,
10225
+ setPressed,
10226
+ getPressedStates,
10227
+ getPressedIndices,
10228
+ cleanup
10229
+ };
10230
+ }
10231
+
9683
10232
  // src/combobox/src/makeComboBoxAccessible.ts
9684
10233
  function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId, listBoxItemsClass, config: config2 }) {
9685
10234
  const comboboxInput = document.getElementById(`${comboboxInputId}`);
@@ -13479,20 +14028,54 @@ async function runContractTests(componentName, component) {
13479
14028
  const staticFailed = 0;
13480
14029
  reporter.reportStatic(staticPassed, staticFailed);
13481
14030
  reporter.summary(failures);
13482
- return { passes, failures };
14031
+ return { passes, failures, skipped };
13483
14032
  }
13484
14033
 
13485
14034
  // src/utils/test/src/test.ts
13486
14035
  async function testUiComponent(componentName, component, url) {
13487
- const results = await axe(component);
14036
+ if (!componentName || typeof componentName !== "string") {
14037
+ throw new Error("\u274C testUiComponent requires a valid componentName (string)");
14038
+ }
14039
+ if (!component || !(component instanceof HTMLElement)) {
14040
+ throw new Error("\u274C testUiComponent requires a valid component (HTMLElement)");
14041
+ }
14042
+ if (url && typeof url !== "string") {
14043
+ throw new Error("\u274C testUiComponent url parameter must be a string");
14044
+ }
14045
+ let results;
14046
+ try {
14047
+ results = await axe(component);
14048
+ } catch (error) {
14049
+ throw new Error(
14050
+ `\u274C Axe accessibility scan failed
14051
+ Error: ${error instanceof Error ? error.message : String(error)}`
14052
+ );
14053
+ }
13488
14054
  let contract;
13489
- if (url) {
13490
- console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
13491
- const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-7U2O33SR.js");
13492
- contract = await runContractTestsPlaywright(componentName, url);
13493
- } else {
13494
- console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
13495
- contract = await runContractTests(componentName, component);
14055
+ try {
14056
+ if (url) {
14057
+ console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
14058
+ try {
14059
+ new URL(url);
14060
+ } catch {
14061
+ throw new Error(
14062
+ `\u274C Invalid URL format: "${url}"
14063
+ URL must include protocol (e.g., "http://localhost:5173/test")`
14064
+ );
14065
+ }
14066
+ const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-UQQI5MYS.js");
14067
+ contract = await runContractTestsPlaywright(componentName, url);
14068
+ } else {
14069
+ console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
14070
+ console.log(`Some tests may be skipped or yield false positives/negatives.
14071
+ For full coverage, run with a URL to enable Playwright E2E tests.`);
14072
+ contract = await runContractTests(componentName, component);
14073
+ }
14074
+ } catch (error) {
14075
+ if (error instanceof Error) {
14076
+ throw error;
14077
+ }
14078
+ throw new Error(`\u274C Contract test execution failed: ${String(error)}`);
13496
14079
  }
13497
14080
  const result = {
13498
14081
  violations: results.violations,
@@ -13503,10 +14086,11 @@ async function testUiComponent(componentName, component, url) {
13503
14086
  const mode = url ? "Playwright" : "jsdom";
13504
14087
  throw new Error(
13505
14088
  `
13506
- \u274C ${contract.failures.length} assertion${contract.failures.length > 1 ? "s" : ""} failed (${mode} mode)
13507
- \u2705 ${contract.passes.length} assertion${contract.passes.length > 1 ? "s" : ""} passed
14089
+ \u274C ${contract.failures.length} accessibility contract test${contract.failures.length > 1 ? "s" : ""} failed (${mode} mode)
14090
+ \u2705 ${contract.passes.length} test${contract.passes.length > 1 ? "s" : ""} passed
13508
14091
 
13509
- \u{1F4CB} Review the detailed test report above for specific failures.`
14092
+ \u{1F4CB} Review the detailed test report above for specific failures.
14093
+ \u{1F4A1} Contract tests validate ARIA attributes and keyboard interactions per W3C APG guidelines.`
13510
14094
  );
13511
14095
  }
13512
14096
  if (results.violations.length > 0) {
@@ -13553,9 +14137,13 @@ if (typeof window === "undefined") {
13553
14137
  };
13554
14138
  }
13555
14139
  export {
14140
+ makeAccordionAccessible,
13556
14141
  makeBlockAccessible,
14142
+ makeCheckboxAccessible,
13557
14143
  makeComboboxAccessible,
13558
14144
  makeMenuAccessible,
14145
+ makeRadioAccessible,
14146
+ makeToggleAccessible,
13559
14147
  testUiComponent,
13560
14148
  updateAccordionTriggerAriaAttributes,
13561
14149
  updateCheckboxAriaAttributes,