aria-ease 2.8.0 → 2.8.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 (82) hide show
  1. package/bin/cli.js +3 -4
  2. package/dist/chunk-PCORWVIQ.js +213 -0
  3. package/dist/{chunk-4F6O5RKZ.js → chunk-SSBW5VAA.js} +0 -1
  4. package/dist/{contractTestRunnerPlaywright-FM6MK6DY.js → contractTestRunnerPlaywright-SE6TPWZZ.js} +1 -2
  5. package/{bin/contractTestRunnerPlaywright-2LQHVMXT.js → dist/contractTestRunnerPlaywright-YNHMLHQ2.js} +6 -178
  6. package/dist/contractTestRunnerPlaywright-ZY2T4UTV.js +254 -0
  7. package/dist/index.cjs +23 -8
  8. package/dist/index.d.cts +11 -14
  9. package/dist/index.d.ts +11 -14
  10. package/dist/index.js +24 -9
  11. package/dist/src/{Types.d-BbztRe-S.d.cts → Types.d-w1KLKLcA.d.cts} +8 -1
  12. package/dist/src/{Types.d-BbztRe-S.d.ts → Types.d-w1KLKLcA.d.ts} +8 -1
  13. package/dist/src/accordion/index.cjs +0 -2
  14. package/dist/src/accordion/index.d.cts +1 -1
  15. package/dist/src/accordion/index.d.ts +1 -1
  16. package/dist/src/accordion/index.js +0 -2
  17. package/dist/src/block/index.cjs +13 -5
  18. package/dist/src/block/index.d.cts +4 -3
  19. package/dist/src/block/index.d.ts +4 -3
  20. package/dist/src/block/index.js +14 -6
  21. package/dist/src/checkbox/index.cjs +0 -2
  22. package/dist/src/checkbox/index.d.cts +1 -1
  23. package/dist/src/checkbox/index.d.ts +1 -1
  24. package/dist/src/checkbox/index.js +0 -2
  25. package/dist/src/{chunk-DF4OR64G.js → chunk-TBJ6MIC7.js} +0 -2
  26. package/dist/src/menu/index.cjs +9 -4
  27. package/dist/src/menu/index.d.cts +4 -11
  28. package/dist/src/menu/index.d.ts +4 -11
  29. package/dist/src/menu/index.js +10 -5
  30. package/dist/src/radio/index.cjs +0 -2
  31. package/dist/src/radio/index.d.cts +1 -1
  32. package/dist/src/radio/index.d.ts +1 -1
  33. package/dist/src/radio/index.js +0 -2
  34. package/dist/src/toggle/index.cjs +0 -2
  35. package/dist/src/toggle/index.d.cts +1 -1
  36. package/dist/src/toggle/index.d.ts +1 -1
  37. package/dist/src/toggle/index.js +0 -2
  38. package/dist/src/utils/test/{chunk-UAS6V5MH.js → chunk-SSBW5VAA.js} +0 -2
  39. package/dist/src/utils/test/{contractTestRunnerPlaywright-IBC4FHWK.js → contractTestRunnerPlaywright-I36Y2NHA.js} +1 -3
  40. package/dist/src/utils/test/contractTestRunnerPlaywright-YNHMLHQ2.js +249 -0
  41. package/dist/src/utils/test/contractTestRunnerPlaywright-ZY2T4UTV.js +249 -0
  42. package/dist/src/utils/test/contracts/MenuContract.json +52 -8
  43. package/dist/src/utils/test/index.cjs +1 -3
  44. package/dist/src/utils/test/index.js +2 -4
  45. package/package.json +14 -13
  46. package/bin/cli.cjs +0 -475
  47. package/bin/cli.cjs.map +0 -1
  48. package/bin/cli.d.cts +0 -1
  49. package/bin/cli.d.ts +0 -1
  50. package/bin/cli.d.ts.map +0 -1
  51. package/bin/cli.js.map +0 -1
  52. package/bin/cli.ts +0 -122
  53. package/bin/configLoader.d.ts +0 -19
  54. package/bin/configLoader.d.ts.map +0 -1
  55. package/bin/configLoader.js +0 -155
  56. package/bin/configLoader.ts +0 -170
  57. package/bin/contractTestRunnerPlaywright-2LQHVMXT.js.map +0 -1
  58. package/dist/chunk-4F6O5RKZ.js.map +0 -1
  59. package/dist/contractTestRunnerPlaywright-FM6MK6DY.js.map +0 -1
  60. package/dist/index.cjs.map +0 -1
  61. package/dist/index.js.map +0 -1
  62. package/dist/src/accordion/index.cjs.map +0 -1
  63. package/dist/src/accordion/index.js.map +0 -1
  64. package/dist/src/block/index.cjs.map +0 -1
  65. package/dist/src/block/index.js.map +0 -1
  66. package/dist/src/checkbox/index.cjs.map +0 -1
  67. package/dist/src/checkbox/index.js.map +0 -1
  68. package/dist/src/chunk-CGC24XEF.js +0 -127
  69. package/dist/src/chunk-CGC24XEF.js.map +0 -1
  70. package/dist/src/chunk-DF4OR64G.js.map +0 -1
  71. package/dist/src/chunk-MNMWQWXH.js +0 -117
  72. package/dist/src/chunk-MNMWQWXH.js.map +0 -1
  73. package/dist/src/menu/index.cjs.map +0 -1
  74. package/dist/src/menu/index.js.map +0 -1
  75. package/dist/src/radio/index.cjs.map +0 -1
  76. package/dist/src/radio/index.js.map +0 -1
  77. package/dist/src/toggle/index.cjs.map +0 -1
  78. package/dist/src/toggle/index.js.map +0 -1
  79. package/dist/src/utils/test/chunk-UAS6V5MH.js.map +0 -1
  80. package/dist/src/utils/test/contractTestRunnerPlaywright-IBC4FHWK.js.map +0 -1
  81. package/dist/src/utils/test/index.cjs.map +0 -1
  82. package/dist/src/utils/test/index.js.map +0 -1
@@ -0,0 +1,254 @@
1
+ import {
2
+ ContractReporter,
3
+ contract_default
4
+ } from "./chunk-SSBW5VAA.js";
5
+
6
+ // src/utils/test/contract/contractTestRunnerPlaywright.ts
7
+ import { chromium } from "playwright";
8
+ import { readFileSync } from "fs";
9
+ async function runContractTestsPlaywright(componentName, url) {
10
+ const reporter = new ContractReporter(true);
11
+ const contractTyped = contract_default;
12
+ const contractPath = contractTyped[componentName]?.path;
13
+ if (!contractPath) {
14
+ throw new Error(`Contract path not found for component: ${componentName}`);
15
+ }
16
+ const resolvedPath = new URL(contractPath, import.meta.url).pathname;
17
+ const contractData = readFileSync(resolvedPath, "utf-8");
18
+ const componentContract = JSON.parse(contractData);
19
+ const totalTests = componentContract.static[0].assertions.length + componentContract.dynamic.length;
20
+ reporter.start(componentName, totalTests);
21
+ const failures = [];
22
+ const passes = [];
23
+ let browser = null;
24
+ try {
25
+ browser = await chromium.launch({ headless: true });
26
+ const context = await browser.newContext();
27
+ const page = await context.newPage();
28
+ await page.goto(url, { waitUntil: "networkidle" });
29
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 9e4 });
30
+ async function resolveRelativeTarget(selector, relative) {
31
+ const items = await page.locator(selector).all();
32
+ switch (relative) {
33
+ case "first":
34
+ return items[0];
35
+ case "second":
36
+ return items[1];
37
+ case "last":
38
+ return items[items.length - 1];
39
+ case "next": {
40
+ const currentIndex = await page.evaluate(([sel]) => {
41
+ const items2 = Array.from(document.querySelectorAll(sel));
42
+ return items2.indexOf(document.activeElement);
43
+ }, [selector]);
44
+ const nextIndex = (currentIndex + 1) % items.length;
45
+ return items[nextIndex];
46
+ }
47
+ case "previous": {
48
+ const currentIndex = await page.evaluate(([sel]) => {
49
+ const items2 = Array.from(document.querySelectorAll(sel));
50
+ return items2.indexOf(document.activeElement);
51
+ }, [selector]);
52
+ const prevIndex = (currentIndex - 1 + items.length) % items.length;
53
+ return items[prevIndex];
54
+ }
55
+ default:
56
+ return null;
57
+ }
58
+ }
59
+ for (const test of componentContract.static[0]?.assertions || []) {
60
+ if (test.target === "relative") continue;
61
+ const targetSelector = componentContract.selectors[test.target];
62
+ if (!targetSelector) {
63
+ failures.push(`Selector for target ${test.target} not found.`);
64
+ continue;
65
+ }
66
+ const target = page.locator(targetSelector).first();
67
+ const exists = await target.count() > 0;
68
+ if (!exists) {
69
+ failures.push(`Target ${test.target} not found.`);
70
+ continue;
71
+ }
72
+ if (!test.expectedValue) {
73
+ const attributes = test.attribute.split(" | ");
74
+ let hasAny = false;
75
+ for (const attr of attributes) {
76
+ const value = await target.getAttribute(attr.trim());
77
+ if (value !== null) {
78
+ hasAny = true;
79
+ break;
80
+ }
81
+ }
82
+ if (!hasAny) {
83
+ failures.push(test.failureMessage + ` None of the attributes "${test.attribute}" are present.`);
84
+ } else {
85
+ passes.push(`At least one of the attributes "${test.attribute}" exists on the element.`);
86
+ }
87
+ } else {
88
+ const attributeValue = await target.getAttribute(test.attribute);
89
+ const expectedValues = test.expectedValue.split(" | ");
90
+ if (!attributeValue || !expectedValues.includes(attributeValue)) {
91
+ failures.push(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
92
+ } else {
93
+ passes.push(`Attribute value matches expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
94
+ }
95
+ }
96
+ }
97
+ for (const dynamicTest of componentContract.dynamic || []) {
98
+ const { action, assertions } = dynamicTest;
99
+ const failuresBeforeTest = failures.length;
100
+ const containerElement = page.locator(componentContract.selectors.container).first();
101
+ const triggerElement = page.locator(componentContract.selectors.trigger).first();
102
+ const isContainerVisible = await containerElement.isVisible();
103
+ if (isContainerVisible) {
104
+ await triggerElement.click();
105
+ await page.waitForTimeout(50);
106
+ }
107
+ for (const act of action) {
108
+ if (act.type === "click") {
109
+ if (act.target === "document") {
110
+ await page.mouse.click(10, 10);
111
+ } else {
112
+ const actionSelector = componentContract.selectors[act.target];
113
+ if (!actionSelector) {
114
+ failures.push(`Selector for action target ${act.target} not found.`);
115
+ continue;
116
+ }
117
+ await page.locator(actionSelector).first().click();
118
+ await page.waitForTimeout(200);
119
+ }
120
+ }
121
+ if (act.type === "keypress" && act.key) {
122
+ const keyMap = {
123
+ "Space": "Space",
124
+ "Enter": "Enter",
125
+ "Escape": "Escape",
126
+ "Arrow Up": "ArrowUp",
127
+ "Arrow Down": "ArrowDown",
128
+ "Arrow Left": "ArrowLeft",
129
+ "Arrow Right": "ArrowRight",
130
+ "Home": "Home",
131
+ "End": "End",
132
+ "Tab": "Tab"
133
+ };
134
+ let keyValue = keyMap[act.key] || act.key;
135
+ if (keyValue === "Space") {
136
+ keyValue = " ";
137
+ } else if (keyValue.includes(" ")) {
138
+ keyValue = keyValue.replace(/ /g, "");
139
+ }
140
+ if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
141
+ await page.waitForTimeout(100);
142
+ await page.keyboard.press(keyValue);
143
+ await page.waitForTimeout(50);
144
+ } else {
145
+ const keypressSelector = componentContract.selectors[act.target];
146
+ if (!keypressSelector) {
147
+ failures.push(`Selector for keypress target ${act.target} not found.`);
148
+ continue;
149
+ }
150
+ const target = page.locator(keypressSelector).first();
151
+ await target.press(keyValue);
152
+ }
153
+ }
154
+ await page.waitForTimeout(100);
155
+ }
156
+ for (const assertion of assertions) {
157
+ let target;
158
+ if (assertion.target === "relative") {
159
+ const relativeSelector = componentContract.selectors.relative;
160
+ if (!relativeSelector) {
161
+ failures.push("Relative selector is not defined in the contract.");
162
+ continue;
163
+ }
164
+ if (!assertion.expectedValue) {
165
+ failures.push("Expected value for relative target is not defined.");
166
+ continue;
167
+ }
168
+ target = await resolveRelativeTarget(relativeSelector, assertion.expectedValue);
169
+ } else {
170
+ const assertionSelector = componentContract.selectors[assertion.target];
171
+ if (!assertionSelector) {
172
+ failures.push(`Selector for assertion target ${assertion.target} not found.`);
173
+ continue;
174
+ }
175
+ target = page.locator(assertionSelector).first();
176
+ }
177
+ if (!target) {
178
+ failures.push(`Target ${assertion.target} not found.`);
179
+ continue;
180
+ }
181
+ if (assertion.assertion === "toBeVisible") {
182
+ const isVisible = await target.isVisible();
183
+ if (isVisible) {
184
+ passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
185
+ } else {
186
+ failures.push(`${assertion.failureMessage}`);
187
+ }
188
+ }
189
+ if (assertion.assertion === "notToBeVisible") {
190
+ const isVisible = await target.isVisible();
191
+ if (!isVisible) {
192
+ passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
193
+ } else {
194
+ failures.push(assertion.failureMessage + ` ${assertion.target} is still visible.`);
195
+ }
196
+ }
197
+ if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
198
+ const attributeValue = await target.getAttribute(assertion.attribute);
199
+ if (attributeValue === assertion.expectedValue) {
200
+ passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
201
+ } else {
202
+ failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
203
+ }
204
+ }
205
+ if (assertion.assertion === "toHaveFocus") {
206
+ const hasFocus = await target.evaluate((el) => el === document.activeElement);
207
+ if (hasFocus) {
208
+ passes.push(`${assertion.target} has focus as expected. Test: "${dynamicTest.description}".`);
209
+ } else {
210
+ failures.push(`${assertion.failureMessage}`);
211
+ }
212
+ }
213
+ if (assertion.assertion === "toHaveRole" && assertion.expectedValue) {
214
+ const roleValue = await target.getAttribute("role");
215
+ if (roleValue === assertion.expectedValue) {
216
+ passes.push(`${assertion.target} has role "${assertion.expectedValue}". Test: "${dynamicTest.description}".`);
217
+ } else {
218
+ failures.push(assertion.failureMessage + ` Expected role "${assertion.expectedValue}", found "${roleValue}".`);
219
+ }
220
+ }
221
+ }
222
+ const failuresAfterTest = failures.length;
223
+ const testPassed = failuresAfterTest === failuresBeforeTest;
224
+ const failureMessage = testPassed ? void 0 : failures[failures.length - 1];
225
+ reporter.reportTest(dynamicTest, testPassed ? "pass" : "fail", failureMessage);
226
+ }
227
+ const staticPassed = componentContract.static[0].assertions.length;
228
+ const staticFailed = 0;
229
+ reporter.reportStatic(staticPassed, staticFailed);
230
+ reporter.summary(failures);
231
+ } catch (error) {
232
+ if (error instanceof Error) {
233
+ if (error.message.includes("Executable doesn't exist")) {
234
+ console.error("\n\u274C Playwright browsers not found!\n");
235
+ console.log("\u{1F4E6} Run: npx playwright install chromium\n");
236
+ failures.push("Playwright browser not installed. Run: npx playwright install chromium");
237
+ } else if (error.message.includes("net::ERR_CONNECTION_REFUSED")) {
238
+ console.error("\n\u274C Cannot connect to dev server!\n");
239
+ console.log(` Make sure your dev server is running at ${url}
240
+ `);
241
+ failures.push(`Dev server not running at ${url}`);
242
+ } else {
243
+ console.error("\u274C Playwright test error:", error.message);
244
+ failures.push(`Test error: ${error.message}`);
245
+ }
246
+ }
247
+ } finally {
248
+ if (browser) await browser.close();
249
+ }
250
+ return { passes, failures };
251
+ }
252
+ export {
253
+ runContractTestsPlaywright
254
+ };
package/dist/index.cjs CHANGED
@@ -9420,7 +9420,7 @@ async function runContractTestsPlaywright(componentName, url) {
9420
9420
  const context = await browser.newContext();
9421
9421
  const page = await context.newPage();
9422
9422
  await page.goto(url, { waitUntil: "networkidle" });
9423
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 5e3 });
9423
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 3e4 });
9424
9424
  async function resolveRelativeTarget(selector, relative) {
9425
9425
  const items = await page.locator(selector).all();
9426
9426
  switch (relative) {
@@ -9817,7 +9817,6 @@ function handleKeyPress(event, elementItems, elementItemIndex, menuElementDiv, t
9817
9817
  }
9818
9818
 
9819
9819
  // src/block/src/makeBlockAccessible/makeBlockAccessible.ts
9820
- var eventListenersMap = /* @__PURE__ */ new Map();
9821
9820
  function makeBlockAccessible(blockId, blockItemsClass) {
9822
9821
  const blockDiv = document.querySelector(`#${blockId}`);
9823
9822
  if (!blockDiv) {
@@ -9825,12 +9824,20 @@ function makeBlockAccessible(blockId, blockItemsClass) {
9825
9824
  return { cleanup: () => {
9826
9825
  } };
9827
9826
  }
9828
- const blockItems = blockDiv.querySelectorAll(`.${blockItemsClass}`);
9827
+ let cachedItems = null;
9828
+ function getItems() {
9829
+ if (!cachedItems) {
9830
+ cachedItems = blockDiv.querySelectorAll(`.${blockItemsClass}`);
9831
+ }
9832
+ return cachedItems;
9833
+ }
9834
+ const blockItems = getItems();
9829
9835
  if (!blockItems || blockItems.length === 0) {
9830
9836
  console.error(`[aria-ease] Element with class="${blockItemsClass}" not found. Make sure the block items exist before calling makeBlockAccessible.`);
9831
9837
  return { cleanup: () => {
9832
9838
  } };
9833
9839
  }
9840
+ const eventListenersMap = /* @__PURE__ */ new Map();
9834
9841
  blockItems.forEach((blockItem) => {
9835
9842
  if (!eventListenersMap.has(blockItem)) {
9836
9843
  const handler = (event) => {
@@ -9851,8 +9858,10 @@ function makeBlockAccessible(blockId, blockItemsClass) {
9851
9858
  }
9852
9859
  });
9853
9860
  }
9854
- ;
9855
- return { cleanup };
9861
+ function refresh() {
9862
+ cachedItems = null;
9863
+ }
9864
+ return { cleanup, refresh };
9856
9865
  }
9857
9866
 
9858
9867
  // src/checkbox/src/updateCheckboxAriaAttributes/updateCheckboxAriaAttributes.ts
@@ -9905,7 +9914,14 @@ function makeMenuAccessible({ menuId, menuItemsClass, triggerId }) {
9905
9914
  }, cleanup: () => {
9906
9915
  } };
9907
9916
  }
9908
- const handlerMap = /* @__PURE__ */ new Map();
9917
+ if (!/^[\w-]+$/.test(menuId)) {
9918
+ console.error("[aria-ease] Invalid menuId: must be alphanumeric");
9919
+ return { openMenu: () => {
9920
+ }, closeMenu: () => {
9921
+ }, cleanup: () => {
9922
+ } };
9923
+ }
9924
+ const handlerMap = /* @__PURE__ */ new WeakMap();
9909
9925
  const submenuInstances = /* @__PURE__ */ new Map();
9910
9926
  let cachedItems = null;
9911
9927
  let filteredItems = null;
@@ -10024,7 +10040,7 @@ function makeMenuAccessible({ menuId, menuItemsClass, triggerId }) {
10024
10040
  setAria(true);
10025
10041
  const items = getFilteredItems();
10026
10042
  addListeners();
10027
- if (items.length > 0) {
10043
+ if (items && items.length > 0) {
10028
10044
  items[0].focus();
10029
10045
  }
10030
10046
  }
@@ -13732,4 +13748,3 @@ react-is/cjs/react-is.development.js:
13732
13748
  * LICENSE file in the root directory of this source tree.
13733
13749
  *)
13734
13750
  */
13735
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -20,6 +20,13 @@ interface JestAxeResult {
20
20
  contract: unknown;
21
21
  }
22
22
 
23
+ interface AccessibilityInstance {
24
+ cleanup: () => void;
25
+ refresh?: () => void;
26
+ openMenu?: () => void;
27
+ closeMenu?: () => void;
28
+ }
29
+
23
30
  /**
24
31
  * Adds screen reader accessibility to accordions. Updates the aria attributes of the accordion trigger button. Trigger button element must possess the following aria attributes; aria-expanded, aria-controls, aria-label (for only non-text triggers).
25
32
  * @param {string} accordionId The id of the accordion triggers parent container.
@@ -35,9 +42,8 @@ declare function updateAccordionTriggerAriaAttributes(accordionId: string, accor
35
42
  * @param {string} blockId The id of the block container.
36
43
  * @param {string} blockItemsClass The shared class of the elements that are children of the block.
37
44
  */
38
- declare function makeBlockAccessible(blockId: string, blockItemsClass: string): {
39
- cleanup: () => void;
40
- };
45
+
46
+ declare function makeBlockAccessible(blockId: string, blockItemsClass: string): AccessibilityInstance;
41
47
 
42
48
  /**
43
49
  * Adds screen reader accessibility to multiple checkboxes. Updates the aria attributes of the checkboxes. Checkbox elements must possess the following aria attributes; aria-checked and aria-label.
@@ -55,21 +61,12 @@ declare function updateCheckboxAriaAttributes(checkboxId: string, checkboxesClas
55
61
  * @param {string} menuItemsClass - The class of the items that are children of the menu.
56
62
  * @param {string} triggerId - The id of the button that triggers the menu.
57
63
  */
64
+
58
65
  declare function makeMenuAccessible({ menuId, menuItemsClass, triggerId }: {
59
66
  menuId: string;
60
67
  menuItemsClass: string;
61
68
  triggerId: string;
62
- }): {
63
- openMenu: () => void;
64
- closeMenu: () => void;
65
- cleanup: () => void;
66
- refresh?: undefined;
67
- } | {
68
- openMenu: () => void;
69
- closeMenu: () => void;
70
- cleanup: () => void;
71
- refresh: () => void;
72
- };
69
+ }): AccessibilityInstance;
73
70
 
74
71
  /**
75
72
  * Adds screen reader accessibility to multiple radio buttons. Updates the aria attributes of the radio buttons. Radio elements must possess the following aria attributes; aria-checked and aria-label.
package/dist/index.d.ts CHANGED
@@ -20,6 +20,13 @@ interface JestAxeResult {
20
20
  contract: unknown;
21
21
  }
22
22
 
23
+ interface AccessibilityInstance {
24
+ cleanup: () => void;
25
+ refresh?: () => void;
26
+ openMenu?: () => void;
27
+ closeMenu?: () => void;
28
+ }
29
+
23
30
  /**
24
31
  * Adds screen reader accessibility to accordions. Updates the aria attributes of the accordion trigger button. Trigger button element must possess the following aria attributes; aria-expanded, aria-controls, aria-label (for only non-text triggers).
25
32
  * @param {string} accordionId The id of the accordion triggers parent container.
@@ -35,9 +42,8 @@ declare function updateAccordionTriggerAriaAttributes(accordionId: string, accor
35
42
  * @param {string} blockId The id of the block container.
36
43
  * @param {string} blockItemsClass The shared class of the elements that are children of the block.
37
44
  */
38
- declare function makeBlockAccessible(blockId: string, blockItemsClass: string): {
39
- cleanup: () => void;
40
- };
45
+
46
+ declare function makeBlockAccessible(blockId: string, blockItemsClass: string): AccessibilityInstance;
41
47
 
42
48
  /**
43
49
  * Adds screen reader accessibility to multiple checkboxes. Updates the aria attributes of the checkboxes. Checkbox elements must possess the following aria attributes; aria-checked and aria-label.
@@ -55,21 +61,12 @@ declare function updateCheckboxAriaAttributes(checkboxId: string, checkboxesClas
55
61
  * @param {string} menuItemsClass - The class of the items that are children of the menu.
56
62
  * @param {string} triggerId - The id of the button that triggers the menu.
57
63
  */
64
+
58
65
  declare function makeMenuAccessible({ menuId, menuItemsClass, triggerId }: {
59
66
  menuId: string;
60
67
  menuItemsClass: string;
61
68
  triggerId: string;
62
- }): {
63
- openMenu: () => void;
64
- closeMenu: () => void;
65
- cleanup: () => void;
66
- refresh?: undefined;
67
- } | {
68
- openMenu: () => void;
69
- closeMenu: () => void;
70
- cleanup: () => void;
71
- refresh: () => void;
72
- };
69
+ }): AccessibilityInstance;
73
70
 
74
71
  /**
75
72
  * Adds screen reader accessibility to multiple radio buttons. Updates the aria attributes of the radio buttons. Radio elements must possess the following aria attributes; aria-checked and aria-label.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  __commonJS,
4
4
  __toESM,
5
5
  contract_default
6
- } from "./chunk-4F6O5RKZ.js";
6
+ } from "./chunk-SSBW5VAA.js";
7
7
 
8
8
  // node_modules/ansi-styles/index.js
9
9
  var require_ansi_styles = __commonJS({
@@ -9331,7 +9331,6 @@ function handleKeyPress(event, elementItems, elementItemIndex, menuElementDiv, t
9331
9331
  }
9332
9332
 
9333
9333
  // src/block/src/makeBlockAccessible/makeBlockAccessible.ts
9334
- var eventListenersMap = /* @__PURE__ */ new Map();
9335
9334
  function makeBlockAccessible(blockId, blockItemsClass) {
9336
9335
  const blockDiv = document.querySelector(`#${blockId}`);
9337
9336
  if (!blockDiv) {
@@ -9339,12 +9338,20 @@ function makeBlockAccessible(blockId, blockItemsClass) {
9339
9338
  return { cleanup: () => {
9340
9339
  } };
9341
9340
  }
9342
- const blockItems = blockDiv.querySelectorAll(`.${blockItemsClass}`);
9341
+ let cachedItems = null;
9342
+ function getItems() {
9343
+ if (!cachedItems) {
9344
+ cachedItems = blockDiv.querySelectorAll(`.${blockItemsClass}`);
9345
+ }
9346
+ return cachedItems;
9347
+ }
9348
+ const blockItems = getItems();
9343
9349
  if (!blockItems || blockItems.length === 0) {
9344
9350
  console.error(`[aria-ease] Element with class="${blockItemsClass}" not found. Make sure the block items exist before calling makeBlockAccessible.`);
9345
9351
  return { cleanup: () => {
9346
9352
  } };
9347
9353
  }
9354
+ const eventListenersMap = /* @__PURE__ */ new Map();
9348
9355
  blockItems.forEach((blockItem) => {
9349
9356
  if (!eventListenersMap.has(blockItem)) {
9350
9357
  const handler = (event) => {
@@ -9365,8 +9372,10 @@ function makeBlockAccessible(blockId, blockItemsClass) {
9365
9372
  }
9366
9373
  });
9367
9374
  }
9368
- ;
9369
- return { cleanup };
9375
+ function refresh() {
9376
+ cachedItems = null;
9377
+ }
9378
+ return { cleanup, refresh };
9370
9379
  }
9371
9380
 
9372
9381
  // src/checkbox/src/updateCheckboxAriaAttributes/updateCheckboxAriaAttributes.ts
@@ -9419,7 +9428,14 @@ function makeMenuAccessible({ menuId, menuItemsClass, triggerId }) {
9419
9428
  }, cleanup: () => {
9420
9429
  } };
9421
9430
  }
9422
- const handlerMap = /* @__PURE__ */ new Map();
9431
+ if (!/^[\w-]+$/.test(menuId)) {
9432
+ console.error("[aria-ease] Invalid menuId: must be alphanumeric");
9433
+ return { openMenu: () => {
9434
+ }, closeMenu: () => {
9435
+ }, cleanup: () => {
9436
+ } };
9437
+ }
9438
+ const handlerMap = /* @__PURE__ */ new WeakMap();
9423
9439
  const submenuInstances = /* @__PURE__ */ new Map();
9424
9440
  let cachedItems = null;
9425
9441
  let filteredItems = null;
@@ -9538,7 +9554,7 @@ function makeMenuAccessible({ menuId, menuItemsClass, triggerId }) {
9538
9554
  setAria(true);
9539
9555
  const items = getFilteredItems();
9540
9556
  addListeners();
9541
- if (items.length > 0) {
9557
+ if (items && items.length > 0) {
9542
9558
  items[0].focus();
9543
9559
  }
9544
9560
  }
@@ -13155,7 +13171,7 @@ async function testUiComponent(componentName, component, url) {
13155
13171
  let contract;
13156
13172
  if (url) {
13157
13173
  console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
13158
- const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-FM6MK6DY.js");
13174
+ const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-YNHMLHQ2.js");
13159
13175
  contract = await runContractTestsPlaywright(componentName, url);
13160
13176
  } else {
13161
13177
  console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
@@ -13242,4 +13258,3 @@ react-is/cjs/react-is.development.js:
13242
13258
  * LICENSE file in the root directory of this source tree.
13243
13259
  *)
13244
13260
  */
13245
- //# sourceMappingURL=index.js.map
@@ -14,4 +14,11 @@ interface ToggleStates {
14
14
  pressed: boolean;
15
15
  }
16
16
 
17
- export type { AccordionStates as A, CheckboxStates as C, RadioStates as R, ToggleStates as T };
17
+ interface AccessibilityInstance {
18
+ cleanup: () => void;
19
+ refresh?: () => void;
20
+ openMenu?: () => void;
21
+ closeMenu?: () => void;
22
+ }
23
+
24
+ export type { AccordionStates as A, CheckboxStates as C, RadioStates as R, ToggleStates as T, AccessibilityInstance as a };
@@ -14,4 +14,11 @@ interface ToggleStates {
14
14
  pressed: boolean;
15
15
  }
16
16
 
17
- export type { AccordionStates as A, CheckboxStates as C, RadioStates as R, ToggleStates as T };
17
+ interface AccessibilityInstance {
18
+ cleanup: () => void;
19
+ refresh?: () => void;
20
+ openMenu?: () => void;
21
+ closeMenu?: () => void;
22
+ }
23
+
24
+ export type { AccordionStates as A, CheckboxStates as C, RadioStates as R, ToggleStates as T, AccessibilityInstance as a };
@@ -27,5 +27,3 @@ function updateAccordionTriggerAriaAttributes(accordionId, accordionTriggersClas
27
27
  }
28
28
 
29
29
  exports.updateAccordionTriggerAriaAttributes = updateAccordionTriggerAriaAttributes;
30
- //# sourceMappingURL=index.cjs.map
31
- //# sourceMappingURL=index.cjs.map
@@ -1,4 +1,4 @@
1
- import { A as AccordionStates } from '../Types.d-BbztRe-S.cjs';
1
+ import { A as AccordionStates } from '../Types.d-w1KLKLcA.cjs';
2
2
 
3
3
  /**
4
4
  * Adds screen reader accessibility to accordions. Updates the aria attributes of the accordion trigger button. Trigger button element must possess the following aria attributes; aria-expanded, aria-controls, aria-label (for only non-text triggers).
@@ -1,4 +1,4 @@
1
- import { A as AccordionStates } from '../Types.d-BbztRe-S.js';
1
+ import { A as AccordionStates } from '../Types.d-w1KLKLcA.js';
2
2
 
3
3
  /**
4
4
  * Adds screen reader accessibility to accordions. Updates the aria attributes of the accordion trigger button. Trigger button element must possess the following aria attributes; aria-expanded, aria-controls, aria-label (for only non-text triggers).
@@ -25,5 +25,3 @@ function updateAccordionTriggerAriaAttributes(accordionId, accordionTriggersClas
25
25
  }
26
26
 
27
27
  export { updateAccordionTriggerAriaAttributes };
28
- //# sourceMappingURL=index.js.map
29
- //# sourceMappingURL=index.js.map
@@ -79,7 +79,6 @@ function handleKeyPress(event, elementItems, elementItemIndex, menuElementDiv, t
79
79
  }
80
80
 
81
81
  // src/block/src/makeBlockAccessible/makeBlockAccessible.ts
82
- var eventListenersMap = /* @__PURE__ */ new Map();
83
82
  function makeBlockAccessible(blockId, blockItemsClass) {
84
83
  const blockDiv = document.querySelector(`#${blockId}`);
85
84
  if (!blockDiv) {
@@ -87,12 +86,20 @@ function makeBlockAccessible(blockId, blockItemsClass) {
87
86
  return { cleanup: () => {
88
87
  } };
89
88
  }
90
- const blockItems = blockDiv.querySelectorAll(`.${blockItemsClass}`);
89
+ let cachedItems = null;
90
+ function getItems() {
91
+ if (!cachedItems) {
92
+ cachedItems = blockDiv.querySelectorAll(`.${blockItemsClass}`);
93
+ }
94
+ return cachedItems;
95
+ }
96
+ const blockItems = getItems();
91
97
  if (!blockItems || blockItems.length === 0) {
92
98
  console.error(`[aria-ease] Element with class="${blockItemsClass}" not found. Make sure the block items exist before calling makeBlockAccessible.`);
93
99
  return { cleanup: () => {
94
100
  } };
95
101
  }
102
+ const eventListenersMap = /* @__PURE__ */ new Map();
96
103
  blockItems.forEach((blockItem) => {
97
104
  if (!eventListenersMap.has(blockItem)) {
98
105
  const handler = (event) => {
@@ -113,9 +120,10 @@ function makeBlockAccessible(blockId, blockItemsClass) {
113
120
  }
114
121
  });
115
122
  }
116
- return { cleanup };
123
+ function refresh() {
124
+ cachedItems = null;
125
+ }
126
+ return { cleanup, refresh };
117
127
  }
118
128
 
119
129
  exports.makeBlockAccessible = makeBlockAccessible;
120
- //# sourceMappingURL=index.cjs.map
121
- //# sourceMappingURL=index.cjs.map
@@ -1,10 +1,11 @@
1
+ import { a as AccessibilityInstance } from '../Types.d-w1KLKLcA.cjs';
2
+
1
3
  /**
2
4
  * Adds keyboard interaction to block. The block traps focus and can be interacted with using the keyboard.
3
5
  * @param {string} blockId The id of the block container.
4
6
  * @param {string} blockItemsClass The shared class of the elements that are children of the block.
5
7
  */
6
- declare function makeBlockAccessible(blockId: string, blockItemsClass: string): {
7
- cleanup: () => void;
8
- };
8
+
9
+ declare function makeBlockAccessible(blockId: string, blockItemsClass: string): AccessibilityInstance;
9
10
 
10
11
  export { makeBlockAccessible };
@@ -1,10 +1,11 @@
1
+ import { a as AccessibilityInstance } from '../Types.d-w1KLKLcA.js';
2
+
1
3
  /**
2
4
  * Adds keyboard interaction to block. The block traps focus and can be interacted with using the keyboard.
3
5
  * @param {string} blockId The id of the block container.
4
6
  * @param {string} blockItemsClass The shared class of the elements that are children of the block.
5
7
  */
6
- declare function makeBlockAccessible(blockId: string, blockItemsClass: string): {
7
- cleanup: () => void;
8
- };
8
+
9
+ declare function makeBlockAccessible(blockId: string, blockItemsClass: string): AccessibilityInstance;
9
10
 
10
11
  export { makeBlockAccessible };