aria-ease 2.2.3 → 2.4.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 +407 -27
  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} +25 -20
  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 +13644 -233
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +102 -7
  21. package/dist/index.d.ts +102 -7
  22. package/dist/index.js +13191 -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 +99 -99
  33. package/dist/src/block/index.cjs.map +1 -1
  34. package/dist/src/block/index.d.cts +4 -2
  35. package/dist/src/block/index.d.ts +4 -2
  36. package/dist/src/block/index.js +42 -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 +33 -12
  76. package/bin/audit-cli.cjs +0 -876
  77. package/bin/audit-cli.cjs.map +0 -1
  78. package/bin/audit-cli.js +0 -779
  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 -239
  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 -232
  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,442 @@
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)
14
33
 
15
- The package currently has support for 6 components: accordions, blocks, checkboxes, menus, radios, toggle butttons.
34
+ Run automated accessibility audits on your website with one command:
35
+
36
+ ```bash
37
+ npx aria-ease audit --url https://yoursite.com
38
+ ```
16
39
 
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.
40
+ This generates comprehensive reports in JSON, CSV, and HTML formats showing all accessibility violations detected by axe-core.
18
41
 
19
- #### Usage
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
+ ```
66
+
67
+ **Supported config formats:**
68
+
69
+ - `ariaease.config.js` (ES modules)
70
+ - `ariaease.config.mjs` (ES modules explicit)
71
+ - `ariaease.config.cjs` (CommonJS)
72
+ - `ariaease.config.json` (JSON)
73
+ - `ariaease.config.ts` (TypeScript - experimental)
74
+
75
+ The CLI will automatically find and load your config file, with validation to catch errors early.
76
+
77
+ **Perfect for CI/CD pipelines** to catch accessibility issues before production!
78
+
79
+ ---
80
+
81
+ ## 📚 Component API
82
+
83
+ ### 🍔 Menu (Dropdowns)
84
+
85
+ Creates accessible menus with focus trapping and keyboard navigation. Works for dropdowns that toggles display with interactive items.
86
+
87
+ **Features:**
88
+
89
+ - Arrow key navigation
90
+ - Escape key closes menu and restores focus
91
+ - Focus trap within menu
92
+ - Submenu support
20
93
 
21
94
  ```javascript
22
95
  import * as Menu from "aria-ease/menu";
23
96
 
97
+ // React Example
24
98
  useEffect(() => {
25
99
  menuRef.current = Menu.makeMenuAccessible({
26
100
  menuId: "menu-div",
27
- menuElementsClass: "profile-menu-items",
101
+ menuItemsClass: "profile-menu-items",
28
102
  triggerId: "display-button",
29
103
  });
104
+
105
+ return () => menuRef.current.cleanup(); // Clean up on unmount
30
106
  }, []);
31
107
 
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
- };
108
+ // Programmatically control
109
+ menuRef.current.openMenu(); // Open the menu
110
+ menuRef.current.closeMenu(); // Close the menu
111
+ menuRef.current.refresh(); // Refresh the cache after dynamically adding/removing a menu item
112
+
113
+ // Vanilla JS Example
114
+ const menu = Menu.makeMenuAccessible({
115
+ menuId: "dropdown-menu",
116
+ menuItemsClass: "menu-item",
117
+ triggerId: "menu-button",
118
+ });
119
+
120
+ // Programmatically control
121
+ menu.openMenu();
122
+ menu.closeMenu();
123
+
124
+ // If you dynamically add/remove menu items, refresh the cache
125
+ menu.refresh();
126
+ ```
127
+
128
+ **Required HTML structure:**
129
+
130
+ ```html
131
+ <button
132
+ id="menu-button"
133
+ aria-expanded="false"
134
+ aria-controls="dropdown-menu"
135
+ aria-haspopup="true"
136
+ >
137
+ Menu
138
+ </button>
139
+ <div
140
+ id="dropdown-menu"
141
+ style="display: none;"
142
+ aria-labelledby="menu-button"
143
+ role="menu"
144
+ >
145
+ <a role="menuitem" href="#" class="menu-item">Item 1</a>
146
+ <a role="menuitem" href="#" class="menu-item">Item 2</a>
147
+ <button role="menuitem" class="menu-item">Item 3</button>
148
+ </div>
149
+ ```
150
+
151
+ ## 🎮 Live Demo
152
+
153
+ - [Menu Component](https://codesandbox.io/p/sandbox/szsclq) - Dropdown with keyboard navigation
154
+
155
+ ---
156
+
157
+ ### 🪗 Accordion
158
+
159
+ Updates `aria-expanded` attributes for accordion panels.
160
+
161
+ ```javascript
162
+ import { updateAccordionTriggerAriaAttributes } from "aria-ease/accordion";
163
+
164
+ const accordionStates = [
165
+ { expanded: true },
166
+ { expanded: false },
167
+ { expanded: false },
168
+ ];
169
+
170
+ // Call when accordion state changes
171
+ updateAccordionTriggerAriaAttributes(
172
+ "accordion-container", // Container ID
173
+ "accordion-trigger", // Shared class for triggers
174
+ accordionStates, // State array
175
+ 0 // Index of trigger that changed
176
+ );
177
+ ```
178
+
179
+ **HTML structure:**
180
+
181
+ ```html
182
+ <div id="accordion-container">
183
+ <button
184
+ class="accordion-trigger"
185
+ aria-expanded="false"
186
+ aria-controls="panel-1"
187
+ >
188
+ Section 1
189
+ </button>
190
+ <div id="panel-1">Content 1</div>
191
+
192
+ <button
193
+ class="accordion-trigger"
194
+ aria-expanded="false"
195
+ aria-controls="panel-2"
196
+ >
197
+ Section 2
198
+ </button>
199
+ <div id="panel-2">Content 2</div>
200
+ </div>
201
+ ```
202
+
203
+ ---
204
+
205
+ ### ✅ Checkbox
206
+
207
+ Updates `aria-checked` attributes for custom checkboxes.
208
+
209
+ ```javascript
210
+ import { updateCheckboxAriaAttributes } from "aria-ease/checkbox";
211
+
212
+ const checkboxStates = [
213
+ { checked: true },
214
+ { checked: false },
215
+ { checked: true },
216
+ ];
217
+
218
+ // Call when checkbox is toggled
219
+ function handleCheckboxClick(index) {
220
+ checkboxStates[index].checked = !checkboxStates[index].checked;
221
+
222
+ updateCheckboxAriaAttributes(
223
+ "checkbox-group",
224
+ "custom-checkbox",
225
+ checkboxStates,
226
+ index
227
+ );
228
+ }
229
+ ```
230
+
231
+ **HTML structure:**
232
+
233
+ ```html
234
+ <div id="checkbox-group">
235
+ <div
236
+ class="custom-checkbox"
237
+ role="checkbox"
238
+ aria-checked="false"
239
+ aria-label="Option 1"
240
+ ></div>
241
+ <div
242
+ class="custom-checkbox"
243
+ role="checkbox"
244
+ aria-checked="false"
245
+ aria-label="Option 2"
246
+ ></div>
247
+ </div>
248
+ ```
249
+
250
+ ---
251
+
252
+ ### 🔘 Radio Button
253
+
254
+ Updates `aria-checked` attributes for custom radio buttons.
255
+
256
+ ```javascript
257
+ import { updateRadioAriaAttributes } from "aria-ease/radio";
258
+
259
+ const radioStates = [{ checked: true }, { checked: false }, { checked: false }];
260
+
261
+ function handleRadioSelect(index) {
262
+ // Uncheck all, check selected
263
+ radioStates.forEach((state, i) => {
264
+ state.checked = i === index;
265
+ });
266
+
267
+ updateRadioAriaAttributes("radio-group", "custom-radio", radioStates);
268
+ }
40
269
  ```
41
270
 
42
- [Check out more features/functionality in the docs](https://ariaease.site/docs)
271
+ ---
43
272
 
44
- [Start contributing on GitHub](https://github.com/aria-ease/aria-ease)
273
+ ### 🔀 Toggle Button
45
274
 
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.
275
+ Updates `aria-pressed` attributes for toggle buttons.
276
+
277
+ ```javascript
278
+ import { updateToggleAriaAttribute } from "aria-ease/toggle";
47
279
 
48
- Aria-ease is open-source software by [Isaac Victor](https://isaacvictordev.web.app/)
280
+ const toggleStates = [{ pressed: false }, { pressed: true }];
281
+
282
+ function handleToggle(index) {
283
+ toggleStates[index].pressed = !toggleStates[index].pressed;
284
+
285
+ updateToggleAriaAttribute("toggle-container", "toggle-btn", toggleStates);
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ### 🧱 Block (Generic Focusable Groups)
292
+
293
+ Makes groups of elements keyboard navigable with arrow keys. Perfect for custom controls, toolbars, or any grouped interactive elements.
294
+
295
+ ```javascript
296
+ import { makeBlockAccessible } from "aria-ease/block";
297
+
298
+ const blockInstance = makeBlockAccessible({
299
+ blockId: "toolbar",
300
+ blockItemsClass: "tool-button",
301
+ });
302
+
303
+ // Clean up when done
304
+ blockInstance.current.cleanup();
305
+ ```
49
306
 
50
- ### P.S. Don't Forget About Focus Styling!
307
+ ---
51
308
 
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.
309
+ ## 🧪 Testing Your Components
310
+
311
+ Aria-Ease includes a built-in testing framework for automated accessibility validation:
312
+
313
+ ```javascript
314
+ import { testUiComponent } from "aria-ease/test";
315
+
316
+ // In your test file (Vitest, Jest, etc.)
317
+ test("menu is accessible", async () => {
318
+ const { container } = render(<MyMenu />);
319
+
320
+ // Runs axe-core + contract tests
321
+ const result = await testUiComponent(
322
+ "menu",
323
+ container,
324
+ "http://localhost:3000" // Optional: full E2E with Playwright
325
+ );
326
+
327
+ expect(result.violations).toHaveLength(0);
328
+ });
329
+ ```
330
+
331
+ ---
332
+
333
+ ## 📦 Bundle Size
334
+
335
+ Aria-Ease is designed to be lightweight and tree-shakable:
336
+
337
+ | Import | Size (ESM) |
338
+ | ---------------------------- | --------------------- |
339
+ | `aria-ease/accordion` | ~1.5KB |
340
+ | `aria-ease/checkbox` | ~1.6KB |
341
+ | `aria-ease/radio` | ~1.6KB |
342
+ | `aria-ease/toggle` | ~1.4KB |
343
+ | `aria-ease/menu` | ~3.7KB |
344
+ | `aria-ease/block` | ~1.7KB |
345
+ | Full bundle (all components) | ~416KB (uncompressed) |
346
+
347
+ **💡 Tip:** Always import individual components for optimal bundle size:
348
+
349
+ ```javascript
350
+ // ✅ Good - only imports menu code (~3.7KB)
351
+ import { makeMenuAccessible } from "aria-ease/menu";
352
+ //or
353
+ import * as Block from "aria-ease/block";
354
+
355
+ // ❌ Avoid - imports everything (~416KB)
356
+ import { makeMenuAccessible } from "aria-ease";
357
+ ```
53
358
 
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.
359
+ ---
55
360
 
56
- Here's a simple CSS example to enhance focus visibility:
361
+ ## ⚠️ Important: React StrictMode
362
+
363
+ If using React StrictMode, be aware it intentionally calls effects twice in development. This can cause issues with imperative DOM manipulation. Either:
364
+
365
+ 1. Remove `<React.StrictMode>` in development, or
366
+ 2. Use proper cleanup functions:
367
+
368
+ ```javascript
369
+ useEffect(() => {
370
+ menuRef.current = Menu.makeMenuAccessible({...});
371
+ return () => menuRef.current.cleanup(); // Prevents double-initialization
372
+ }, []);
373
+ ```
374
+
375
+ ---
376
+
377
+ ## 🎨 Focus Styling
378
+
379
+ Aria-Ease handles ARIA attributes and keyboard navigation, but **you must provide visible focus styles**:
57
380
 
58
381
  ```css
59
382
  :focus {
60
- outline: 2px solid rgba(0, 91, 211, 1); /* Blue outline for high contrast */
61
- outline-offset: 1px;
383
+ outline: 2px solid rgba(0, 91, 211, 1);
384
+ outline-offset: 2px;
385
+ }
386
+
387
+ /* Or custom styles */
388
+ .menu-item:focus {
389
+ background: #e3f2fd;
390
+ box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.3);
62
391
  }
63
392
  ```
393
+
394
+ Without visible focus indicators, keyboard users cannot tell which element is active.
395
+
396
+ ---
397
+
398
+ ## 🌐 Browser Support
399
+
400
+ Aria-Ease supports all modern browsers:
401
+
402
+ | Browser | Minimum Version |
403
+ | ------- | --------------- |
404
+ | Chrome | Last 2 versions |
405
+ | Firefox | Last 2 versions |
406
+ | Safari | Last 2 versions |
407
+ | Edge | Last 2 versions |
408
+
409
+ **Not supported:** Internet Explorer 11 and below
410
+
411
+ **Requirements:**
412
+
413
+ - ES6+ support
414
+ - `querySelector` and `querySelectorAll`
415
+ - `addEventListener` and `removeEventListener`
416
+ - Modern event handling (`KeyboardEvent`, `FocusEvent`)
417
+
418
+ For older browser support, use a polyfill service or transpile with appropriate targets.
419
+
420
+ ---
421
+
422
+ ## 📖 More Resources
423
+
424
+ - [Full Documentation](https://ariaease.site/docs)
425
+ - [GitHub Repository](https://github.com/aria-ease/aria-ease)
426
+ - [Report Issues](https://github.com/aria-ease/aria-ease/issues)
427
+ - [Contributing Guide](https://github.com/aria-ease/aria-ease/blob/main/CONTRIBUTION-GUIDELINES.md)
428
+
429
+ ---
430
+
431
+ ## 🤝 Contributing
432
+
433
+ We welcome contributions! See our [contribution guidelines](CONTRIBUTION-GUIDELINES.md) to get started.
434
+
435
+ ---
436
+
437
+ ## 📄 License
438
+
439
+ ISC License - see [LICENSE](LICENSE) file for details.
440
+
441
+ ---
442
+
443
+ **Created by [Isaac Victor](https://github.com/Scriptkidd98)**