aria-ease 2.2.2 → 2.3.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 (101) hide show
  1. package/README.md +387 -30
  2. package/bin/cli.cjs +475 -0
  3. package/bin/cli.cjs.map +1 -0
  4. package/bin/cli.d.ts.map +1 -0
  5. package/bin/cli.js +452 -0
  6. package/bin/cli.js.map +1 -0
  7. package/bin/{audit-cli.ts → cli.ts} +35 -26
  8. package/bin/configLoader.d.ts +19 -0
  9. package/bin/configLoader.d.ts.map +1 -0
  10. package/bin/configLoader.js +155 -0
  11. package/bin/configLoader.ts +170 -0
  12. package/bin/contractTestRunnerPlaywright-2LQHVMXT.js +426 -0
  13. package/bin/contractTestRunnerPlaywright-2LQHVMXT.js.map +1 -0
  14. package/dist/chunk-4F6O5RKZ.js +207 -0
  15. package/dist/chunk-4F6O5RKZ.js.map +1 -0
  16. package/dist/contractTestRunnerPlaywright-FM6MK6DY.js +255 -0
  17. package/dist/contractTestRunnerPlaywright-FM6MK6DY.js.map +1 -0
  18. package/dist/index.cjs +13642 -233
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +100 -7
  21. package/dist/index.d.ts +100 -7
  22. package/dist/index.js +13189 -7
  23. package/dist/index.js.map +1 -1
  24. package/dist/{Types.d-p85gN5m_.d.cts → src/Types.d-BbztRe-S.d.cts} +0 -5
  25. package/dist/{Types.d-p85gN5m_.d.ts → src/Types.d-BbztRe-S.d.ts} +0 -5
  26. package/dist/src/accordion/index.cjs +25 -19
  27. package/dist/src/accordion/index.cjs.map +1 -1
  28. package/dist/src/accordion/index.d.cts +1 -1
  29. package/dist/src/accordion/index.d.ts +1 -1
  30. package/dist/src/accordion/index.js +28 -1
  31. package/dist/src/accordion/index.js.map +1 -1
  32. package/dist/src/block/index.cjs +98 -99
  33. package/dist/src/block/index.cjs.map +1 -1
  34. package/dist/src/block/index.d.cts +2 -2
  35. package/dist/src/block/index.d.ts +2 -2
  36. package/dist/src/block/index.js +41 -2
  37. package/dist/src/block/index.js.map +1 -1
  38. package/dist/src/checkbox/index.cjs +30 -13
  39. package/dist/src/checkbox/index.cjs.map +1 -1
  40. package/dist/src/checkbox/index.d.cts +1 -1
  41. package/dist/src/checkbox/index.d.ts +1 -1
  42. package/dist/src/checkbox/index.js +33 -1
  43. package/dist/src/checkbox/index.js.map +1 -1
  44. package/dist/src/chunk-MNMWQWXH.js +117 -0
  45. package/dist/src/chunk-MNMWQWXH.js.map +1 -0
  46. package/dist/src/menu/index.cjs +208 -130
  47. package/dist/src/menu/index.cjs.map +1 -1
  48. package/dist/src/menu/index.d.cts +9 -3
  49. package/dist/src/menu/index.d.ts +9 -3
  50. package/dist/src/menu/index.js +118 -2
  51. package/dist/src/menu/index.js.map +1 -1
  52. package/dist/src/radio/index.cjs +29 -16
  53. package/dist/src/radio/index.cjs.map +1 -1
  54. package/dist/src/radio/index.d.cts +1 -1
  55. package/dist/src/radio/index.d.ts +1 -1
  56. package/dist/src/radio/index.js +32 -1
  57. package/dist/src/radio/index.js.map +1 -1
  58. package/dist/src/toggle/index.cjs +26 -16
  59. package/dist/src/toggle/index.cjs.map +1 -1
  60. package/dist/src/toggle/index.d.cts +1 -1
  61. package/dist/src/toggle/index.d.ts +1 -1
  62. package/dist/src/toggle/index.js +29 -1
  63. package/dist/src/toggle/index.js.map +1 -1
  64. package/dist/src/utils/test/chunk-UAS6V5MH.js +203 -0
  65. package/dist/src/utils/test/chunk-UAS6V5MH.js.map +1 -0
  66. package/dist/src/utils/test/contractTestRunnerPlaywright-IBC4FHWK.js +251 -0
  67. package/dist/src/utils/test/contractTestRunnerPlaywright-IBC4FHWK.js.map +1 -0
  68. package/dist/src/utils/test/contracts/MenuContract.json +343 -0
  69. package/dist/src/utils/test/index.cjs +13092 -0
  70. package/dist/src/utils/test/index.cjs.map +1 -0
  71. package/dist/src/utils/test/index.d.cts +16 -0
  72. package/dist/src/utils/test/index.d.ts +16 -0
  73. package/dist/src/utils/test/index.js +12608 -0
  74. package/dist/src/utils/test/index.js.map +1 -0
  75. package/package.json +27 -12
  76. package/bin/audit-cli.cjs +0 -841
  77. package/bin/audit-cli.cjs.map +0 -1
  78. package/bin/audit-cli.js +0 -744
  79. package/bin/audit-cli.js.map +0 -1
  80. package/dist/chunk-4366LRNM.js +0 -38
  81. package/dist/chunk-4366LRNM.js.map +0 -1
  82. package/dist/chunk-5HQ6LLC5.js +0 -21
  83. package/dist/chunk-5HQ6LLC5.js.map +0 -1
  84. package/dist/chunk-FBQ5LF2T.js +0 -21
  85. package/dist/chunk-FBQ5LF2T.js.map +0 -1
  86. package/dist/chunk-KVTLMA4J.js +0 -58
  87. package/dist/chunk-KVTLMA4J.js.map +0 -1
  88. package/dist/chunk-MEA5U2G4.js +0 -24
  89. package/dist/chunk-MEA5U2G4.js.map +0 -1
  90. package/dist/chunk-RK3JUAFZ.js +0 -18
  91. package/dist/chunk-RK3JUAFZ.js.map +0 -1
  92. package/dist/chunk-RT5IROW4.js +0 -99
  93. package/dist/chunk-RT5IROW4.js.map +0 -1
  94. package/dist/src/utils/audit/audit.cjs +0 -234
  95. package/dist/src/utils/audit/audit.cjs.map +0 -1
  96. package/dist/src/utils/audit/audit.d.cts +0 -5
  97. package/dist/src/utils/audit/audit.d.ts +0 -5
  98. package/dist/src/utils/audit/audit.js +0 -227
  99. package/dist/src/utils/audit/audit.js.map +0 -1
  100. /package/bin/{audit-cli.d.cts → cli.d.cts} +0 -0
  101. /package/bin/{audit-cli.d.ts → cli.d.ts} +0 -0
package/README.md CHANGED
@@ -2,62 +2,419 @@
2
2
 
3
3
  Out of the box accessibility utility package to develop production ready applications.
4
4
 
5
- ## Install
5
+ [![npm version](https://img.shields.io/npm/v/aria-ease.svg)](https://www.npmjs.com/package/aria-ease)
6
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
7
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/aria-ease)](https://bundlephobia.com/package/aria-ease)
8
+ [![npm downloads](https://img.shields.io/npm/dm/aria-ease.svg)](https://www.npmjs.com/package/aria-ease)
6
9
 
7
- `npm i aria-ease`
10
+ ## Features
8
11
 
9
- `yarn add aria-ease`
12
+ - 🎯 **Tree-shakable** - Import only what you need (1.4KB - 3.7KB per component)
13
+ - ♿ **WCAG Compliant** - Follows WAI-ARIA best practices
14
+ - ⌨️ **Keyboard Navigation** - Full keyboard support out of the box
15
+ - 🧪 **Contract Testing** - Built-in accessibility testing framework
16
+ - 🎭 **Framework Agnostic** - Works with React, Vue, vanilla JS, etc.
17
+ - 🔍 **CLI Audit Tool** - Automated accessibility testing for your sites
18
+ - 📦 **TypeScript Support** - Full type definitions included
10
19
 
11
- ## Features
20
+ ## 📦 Installation
12
21
 
13
- Don't spend hours wrestling with accessibility code. Aria-Ease provides pre-built functions that help you integrate accessibility seamlessly into your development workflow. It simplifies the process of adding essential accessibility features (e.g. assistive capability, keyboard navigation, focus management) to common UI components like menus, accordions, checkboxes, e.t.c. This allows you to focus on building great user experiences for everyone.
22
+ ```bash
23
+ npm i aria-ease
24
+ # or
25
+ yarn add aria-ease
26
+ # or
27
+ pnpm add aria-ease
28
+ ```
29
+
30
+ ## 🚀 Quick Start
31
+
32
+ ### Automated Accessibility Audits (CLI)
33
+
34
+ Run automated accessibility audits on your website with one command:
35
+
36
+ ```bash
37
+ npx aria-ease audit --url https://yoursite.com
38
+ ```
39
+
40
+ This generates comprehensive reports in JSON, CSV, and HTML formats showing all accessibility violations detected by axe-core.
41
+
42
+ **Create a config file** for multiple pages and custom settings:
43
+
44
+ ```javascript
45
+ // ariaease.config.js (or .mjs, .cjs, .json, .ts)
46
+ export default {
47
+ audit: {
48
+ urls: [
49
+ "https://yoursite.com",
50
+ "https://yoursite.com/about",
51
+ "https://yoursite.com/contact",
52
+ ],
53
+ output: {
54
+ format: "html", // 'json' | 'csv' | 'html' | 'all'
55
+ out: "./accessibility-reports",
56
+ }
57
+ }
58
+ };
59
+ ```
60
+
61
+ Then run:
62
+
63
+ ```bash
64
+ npx aria-ease audit
65
+ ```
14
66
 
15
- The package currently has support for 6 components: accordions, blocks, checkboxes, menus, radios, toggle butttons.
67
+ **Supported config formats:**
68
+ - `ariaease.config.js` (ES modules)
69
+ - `ariaease.config.mjs` (ES modules explicit)
70
+ - `ariaease.config.cjs` (CommonJS)
71
+ - `ariaease.config.json` (JSON)
72
+ - `ariaease.config.ts` (TypeScript - experimental)
16
73
 
17
- Add accessibility to menu: menu can be a dropdown, combo box, slide navigation menu, e.t.c. Basically any component that toggles display and has a list of interactive children items. The function creates a focus trap within the menu and focus can be navigated using the arrow keys. The escape key also closes the menu and returns the focus back to the trigger.
74
+ The CLI will automatically find and load your config file, with validation to catch errors early.
18
75
 
19
- #### Usage
76
+ **Perfect for CI/CD pipelines** to catch accessibility issues before production!
77
+
78
+ ---
79
+
80
+ ## 📚 Component API
81
+
82
+ ### 🍔 Menu (Dropdowns, Combo Boxes, Navigation)
83
+
84
+ Creates accessible menus with focus trapping and keyboard navigation. Works for dropdowns, combo boxes, navigation menus - any component that toggles display with interactive items.
85
+
86
+ **Features:**
87
+
88
+ - Arrow key navigation
89
+ - Escape key closes menu and restores focus
90
+ - Focus trap within menu
91
+ - Submenu support
20
92
 
21
93
  ```javascript
22
94
  import * as Menu from "aria-ease/menu";
23
95
 
96
+ // React Example
24
97
  useEffect(() => {
25
- menuRef.current = Menu.makeMenuAccessible({
26
- menuId: "menu-div",
27
- menuElementsClass: "profile-menu-items",
28
- triggerId: "display-button",
98
+ const menuInstance = Menu.makeMenuAccessible({
99
+ menuId: "dropdown-menu",
100
+ menuItemsClass: "menu-item",
101
+ triggerId: "menu-button",
29
102
  });
103
+
104
+ return () => menuInstance.cleanup(); // Clean up on unmount
30
105
  }, []);
31
106
 
32
- const toggleMenuDisplay = () => {
33
- const menuDiv = document.querySelector("#menu-div");
34
- if (getComputedStyle(menuDiv).display === "none") {
35
- menuRef.current.openMenu();
36
- } else {
37
- menuRef.current.closeMenu();
38
- }
39
- };
107
+ // Vanilla JS Example
108
+ const menu = Menu.makeMenuAccessible({
109
+ menuId: "dropdown-menu",
110
+ menuItemsClass: "menu-item",
111
+ triggerId: "menu-button",
112
+ });
113
+
114
+ // Programmatically control
115
+ menu.openMenu();
116
+ menu.closeMenu();
117
+
118
+ // If you dynamically add/remove menu items, refresh the cache
119
+ menu.refresh();
120
+ ```
121
+
122
+ **Required HTML structure:**
123
+
124
+ ```html
125
+ <button id="menu-button" aria-expanded="false" aria-controls="dropdown-menu">
126
+ Menu
127
+ </button>
128
+ <div id="dropdown-menu" style="display: none;">
129
+ <a href="#" class="menu-item">Item 1</a>
130
+ <a href="#" class="menu-item">Item 2</a>
131
+ <button class="menu-item">Item 3</button>
132
+ </div>
133
+ ```
134
+
135
+ ---
136
+
137
+ ### 🪗 Accordion
138
+
139
+ Updates `aria-expanded` attributes for accordion panels.
140
+
141
+ ```javascript
142
+ import { updateAccordionTriggerAriaAttributes } from "aria-ease/accordion";
143
+
144
+ const accordionStates = [
145
+ { expanded: true },
146
+ { expanded: false },
147
+ { expanded: false },
148
+ ];
149
+
150
+ // Call when accordion state changes
151
+ updateAccordionTriggerAriaAttributes(
152
+ "accordion-container", // Container ID
153
+ "accordion-trigger", // Shared class for triggers
154
+ accordionStates, // State array
155
+ 0 // Index of trigger that changed
156
+ );
157
+ ```
158
+
159
+ **HTML structure:**
160
+
161
+ ```html
162
+ <div id="accordion-container">
163
+ <button
164
+ class="accordion-trigger"
165
+ aria-expanded="false"
166
+ aria-controls="panel-1"
167
+ >
168
+ Section 1
169
+ </button>
170
+ <div id="panel-1">Content 1</div>
171
+
172
+ <button
173
+ class="accordion-trigger"
174
+ aria-expanded="false"
175
+ aria-controls="panel-2"
176
+ >
177
+ Section 2
178
+ </button>
179
+ <div id="panel-2">Content 2</div>
180
+ </div>
181
+ ```
182
+
183
+ ---
184
+
185
+ ### ✅ Checkbox
186
+
187
+ Updates `aria-checked` attributes for custom checkboxes.
188
+
189
+ ```javascript
190
+ import { updateCheckboxAriaAttributes } from "aria-ease/checkbox";
191
+
192
+ const checkboxStates = [
193
+ { checked: true },
194
+ { checked: false },
195
+ { checked: true },
196
+ ];
197
+
198
+ // Call when checkbox is toggled
199
+ function handleCheckboxClick(index) {
200
+ checkboxStates[index].checked = !checkboxStates[index].checked;
201
+
202
+ updateCheckboxAriaAttributes(
203
+ "checkbox-group",
204
+ "custom-checkbox",
205
+ checkboxStates,
206
+ index
207
+ );
208
+ }
40
209
  ```
41
210
 
42
- [Check out more features/functionality in the docs](https://ariaease.site/docs)
211
+ **HTML structure:**
212
+
213
+ ```html
214
+ <div id="checkbox-group">
215
+ <div
216
+ class="custom-checkbox"
217
+ role="checkbox"
218
+ aria-checked="false"
219
+ aria-label="Option 1"
220
+ ></div>
221
+ <div
222
+ class="custom-checkbox"
223
+ role="checkbox"
224
+ aria-checked="false"
225
+ aria-label="Option 2"
226
+ ></div>
227
+ </div>
228
+ ```
229
+
230
+ ---
231
+
232
+ ### 🔘 Radio Button
43
233
 
44
- [Start contributing on GitHub](https://github.com/aria-ease/aria-ease)
234
+ Updates `aria-checked` attributes for custom radio buttons.
45
235
 
46
- Find a bug? Head on over to [issue page](https://github.com/aria-ease/aria-ease/issues) and open one. We're excited to receive pull requests.
236
+ ```javascript
237
+ import { updateRadioAriaAttributes } from "aria-ease/radio";
238
+
239
+ const radioStates = [{ checked: true }, { checked: false }, { checked: false }];
240
+
241
+ function handleRadioSelect(index) {
242
+ // Uncheck all, check selected
243
+ radioStates.forEach((state, i) => {
244
+ state.checked = i === index;
245
+ });
47
246
 
48
- Aria-ease is open-source software by [Isaac Victor](https://isaacvictordev.web.app/)
247
+ updateRadioAriaAttributes("radio-group", "custom-radio", radioStates);
248
+ }
249
+ ```
49
250
 
50
- ### P.S. Don't Forget About Focus Styling!
251
+ ---
51
252
 
52
- While Aria-Ease significantly aids in making your web applications more accessible, it's essential to remember that visual cues play a crucial role in accessibility. This is especially true for keyboard navigation, where focus styling indicates which element is currently selectable or active.
253
+ ### 🔀 Toggle Button
53
254
 
54
- Without clear focus styling, users who rely on keyboard navigation may find it challenging to determine which part of the page they are interacting with. Therefore, we strongly encourage you to implement distinct focus styles for interactive elements on your web pages.
255
+ Updates `aria-pressed` attributes for toggle buttons.
256
+
257
+ ```javascript
258
+ import { updateToggleAriaAttribute } from "aria-ease/toggle";
55
259
 
56
- Here's a simple CSS example to enhance focus visibility:
260
+ const toggleStates = [{ pressed: false }, { pressed: true }];
261
+
262
+ function handleToggle(index) {
263
+ toggleStates[index].pressed = !toggleStates[index].pressed;
264
+
265
+ updateToggleAriaAttribute("toggle-container", "toggle-btn", toggleStates);
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ### 🧱 Block (Generic Focusable Groups)
272
+
273
+ Makes groups of elements keyboard navigable with arrow keys. Perfect for custom controls, toolbars, or any grouped interactive elements.
274
+
275
+ ```javascript
276
+ import { makeBlockAccessible } from "aria-ease/block";
277
+
278
+ const blockInstance = makeBlockAccessible({
279
+ blockId: "toolbar",
280
+ blockItemsClass: "tool-button",
281
+ });
282
+
283
+ // Clean up when done
284
+ blockInstance.cleanup();
285
+ ```
286
+
287
+ ---
288
+
289
+ ## 🧪 Testing Your Components
290
+
291
+ Aria-Ease includes a built-in testing framework for automated accessibility validation:
292
+
293
+ ```javascript
294
+ import { testUiComponent } from "aria-ease/test";
295
+
296
+ // In your test file (Vitest, Jest, etc.)
297
+ test("menu is accessible", async () => {
298
+ const { container } = render(<MyMenu />);
299
+
300
+ // Runs axe-core + contract tests
301
+ const result = await testUiComponent(
302
+ "menu",
303
+ container,
304
+ "http://localhost:3000" // Optional: full E2E with Playwright
305
+ );
306
+
307
+ expect(result.violations).toHaveLength(0);
308
+ });
309
+ ```
310
+
311
+ ---
312
+
313
+ ## 📦 Bundle Size
314
+
315
+ Aria-Ease is designed to be lightweight and tree-shakable:
316
+
317
+ | Import | Size (ESM) |
318
+ | ---------------------------- | --------------------- |
319
+ | `aria-ease/accordion` | ~1.5KB |
320
+ | `aria-ease/checkbox` | ~1.6KB |
321
+ | `aria-ease/radio` | ~1.6KB |
322
+ | `aria-ease/toggle` | ~1.4KB |
323
+ | `aria-ease/menu` | ~3.7KB |
324
+ | `aria-ease/block` | ~1.7KB |
325
+ | Full bundle (all components) | ~416KB (uncompressed) |
326
+
327
+ **💡 Tip:** Always import individual components for optimal bundle size:
328
+
329
+ ```javascript
330
+ // ✅ Good - only imports menu code (~3.7KB)
331
+ import { makeMenuAccessible } from "aria-ease/menu";
332
+
333
+ // ❌ Avoid - imports everything (~416KB)
334
+ import { makeMenuAccessible } from "aria-ease";
335
+ ```
336
+
337
+ ---
338
+
339
+ ## ⚠️ Important: React StrictMode
340
+
341
+ If using React StrictMode, be aware it intentionally calls effects twice in development. This can cause issues with imperative DOM manipulation. Either:
342
+
343
+ 1. Remove `<React.StrictMode>` in development, or
344
+ 2. Use proper cleanup functions:
345
+
346
+ ```javascript
347
+ useEffect(() => {
348
+ const instance = makeMenuAccessible({...});
349
+ return () => instance.cleanup(); // Prevents double-initialization
350
+ }, []);
351
+ ```
352
+
353
+ ---
354
+
355
+ ## 🎨 Focus Styling
356
+
357
+ Aria-Ease handles ARIA attributes and keyboard navigation, but **you must provide visible focus styles**:
57
358
 
58
359
  ```css
59
360
  :focus {
60
- outline: 2px solid rgba(0, 91, 211, 1); /* Blue outline for high contrast */
61
- outline-offset: 1px;
361
+ outline: 2px solid rgba(0, 91, 211, 1);
362
+ outline-offset: 2px;
363
+ }
364
+
365
+ /* Or custom styles */
366
+ .menu-item:focus {
367
+ background: #e3f2fd;
368
+ box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.3);
62
369
  }
63
370
  ```
371
+
372
+ Without visible focus indicators, keyboard users cannot tell which element is active.
373
+
374
+ ---
375
+
376
+ ## 🌐 Browser Support
377
+
378
+ Aria-Ease supports all modern browsers:
379
+
380
+ | Browser | Minimum Version |
381
+ |---------|----------------|
382
+ | Chrome | Last 2 versions |
383
+ | Firefox | Last 2 versions |
384
+ | Safari | Last 2 versions |
385
+ | Edge | Last 2 versions |
386
+
387
+ **Not supported:** Internet Explorer 11 and below
388
+
389
+ **Requirements:**
390
+ - ES6+ support
391
+ - `querySelector` and `querySelectorAll`
392
+ - `addEventListener` and `removeEventListener`
393
+ - Modern event handling (`KeyboardEvent`, `FocusEvent`)
394
+
395
+ For older browser support, use a polyfill service or transpile with appropriate targets.
396
+
397
+ ---
398
+
399
+ ## 📖 More Resources
400
+
401
+ - [Full Documentation](https://ariaease.site/docs)
402
+ - [GitHub Repository](https://github.com/aria-ease/aria-ease)
403
+ - [Report Issues](https://github.com/aria-ease/aria-ease/issues)
404
+ - [Contributing Guide](https://github.com/aria-ease/aria-ease/blob/main/CONTRIBUTION-GUIDELINES.md)
405
+
406
+ ---
407
+
408
+ ## 🤝 Contributing
409
+
410
+ We welcome contributions! See our [contribution guidelines](CONTRIBUTION-GUIDELINES.md) to get started.
411
+
412
+ ---
413
+
414
+ ## 📄 License
415
+
416
+ ISC License - see [LICENSE](LICENSE) file for details.
417
+
418
+ ---
419
+
420
+ **Created by [Isaac Victor](https://isaacvictordev.web.app/)**