@shalii/galaxy-a11y 0.1.2 → 0.1.4

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 (2) hide show
  1. package/README.md +171 -11
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Static **WCAG 2.2 / ADA accessibility scanner for Galaxy CMS themes** (html, scss, js).
4
4
  It understands Galaxy syntax (`#$variable|x$#`, `{if="…"}`, `[[id]]`, `__@@text@@__`), so every finding points to the real line in your real file and comes with the exact fix.
5
5
 
6
- > Static scanning finds roughly a third to a half of WCAG problems. See [Limits](#limits) and the manual checklist at the end of every report.
6
+ > Static scanning finds roughly a third to a half of WCAG problems. See [Limits](#6-limits) and the manual checklist at the end of every report.
7
7
 
8
8
  ---
9
9
 
@@ -84,21 +84,181 @@ A non-zero exit code blocks the build or commit when errors exist.
84
84
 
85
85
  ---
86
86
 
87
- ## 3. Rules
87
+ ## 3. What it checks
88
88
 
89
- HTML_LANG · LANG · TITLE · ZOOM · REFRESH · ALT (IMG) · MAP-AREA · SVG · MEDIA · AUDIO · AUDIO-CAPTIONS · ANIMATION · FLASH ·
90
- ERR-LINK · HREF · SKIP-LINK · NAV · HEADING · SEMANTIC · LABEL · LABEL-IN-NAME · INPUT-PURPOSE · AUTOFILL · AUTH · REDUNDANT-ENTRY · ERROR-SUGGESTION · STATUS-LIVE ·
91
- TABINDEX · KEYBOARD · FOCUS · FOCUS-ELEMENT · FOCUS-STRATEGY · TRAP · SHORTCUT · CHAR-KEYS · MODALITY · GESTURE · PTR-GESTURE ·
92
- ARIA · ARIA-ROLE · CONTRAST · COLOR · SIZE · SIZE-2.2 · ORIENTATION · SENSORY · CONSISTENT-HELP (manual).
89
+ **48 rules** (46 automatic + 2 manual-only), made up of about **100 individual checks**, each mapped to a WCAG 2.2 success criterion. Every finding shows the rule name, the WCAG number, the line and column, and the fix.
90
+
91
+ | Area | Rule | What it catches | WCAG |
92
+ |---|---|---|---|
93
+ | **Images and media** | `ALT` | `<img>` with no `alt`, or an `alt` that is only whitespace (suggests the Galaxy variable when the editor controls the alt) | 1.1.1 |
94
+ | | `MAP-AREA` | `<area>` in an image map with no alt text | 1.1.1 / 2.4.4 |
95
+ | | `SVG` | Inline `<svg>` exposed to screen readers without a name (decorative ones should be `aria-hidden`) | 1.1.1 / 4.1.2 |
96
+ | | `MEDIA` | Embedded or `<video>` that autoplays with sound, has no controls, or has no text alternative | 1.4.2 / 2.2.2 |
97
+ | | `AUDIO` | `<audio>` that autoplays | 1.4.2 |
98
+ | | `AUDIO-CAPTIONS` | Embedded video: reminds you to confirm captions / transcript exist | 1.2.2 / 1.2.3 / 1.2.5 |
99
+ | **Motion and timing** | `ANIMATION` | Infinite animations with no `prefers-reduced-motion` override; autoplay video with no pause | 2.2.2 / 2.3.3 |
100
+ | | `FLASH` | Animations repeating faster than 3 times per second | 2.3.1 |
101
+ | | `REFRESH` | Meta refresh and timed redirects | 2.2.1 / 2.2.4 / 3.2.5 |
102
+ | **Page structure** | `HTML_LANG` / `LANG` | Missing or invalid `lang` attribute | 3.1.1 / 3.1.2 |
103
+ | | `TITLE` | Empty or missing `<title>` | 2.4.2 |
104
+ | | `PARSING` | Duplicate `id`s (breaks labels, ARIA and skip links) | 4.1.2 |
105
+ | | `HEADING` | Empty headings, skipped levels (h2 → h4), more than one `<h1>`, and elements styled as headings but not real heading tags | 1.3.1 / 2.4.6 |
106
+ | | `NAV` | No `<main>`, several unlabelled `<nav>` landmarks, links opening a new window without warning | 1.3.1 / 2.4.1 / 3.2.5 |
107
+ | | `SKIP-LINK` | No skip-to-content link in the header, or a skip button with no JS handler | 2.4.1 |
108
+ | | `SEMANTIC` | Interactive elements nested inside each other (`<a>` in `<button>`) | 4.1.2 |
109
+ | **Links and buttons** | `HREF` | `<a>` with no `href` (not keyboard-focusable) | 2.1.1 / 4.1.2 |
110
+ | | `ERR-LINK` | Dead links (`#`, `javascript:`), unclear link text ("click here"), and empty hidden links that screen readers still announce | 2.1.1 / 2.4.4 / 4.1.2 |
111
+ | | `LABEL` | Buttons and inputs with no accessible name, empty `<label>`, `<fieldset>` with no `<legend>`, placeholder-only fields | 1.3.1 / 3.3.2 / 4.1.2 |
112
+ | | `LABEL-IN-NAME` | `aria-label` that does not contain the visible text | 2.5.3 |
113
+ | **Forms** | `INPUT-PURPOSE` | Personal-data fields (name, email, phone…) with no `autocomplete` | 1.3.5 |
114
+ | | `AUTOFILL` | `autocomplete="off"` on personal-data fields | 1.3.5 / 3.3.7 |
115
+ | | `AUTH` | Password fields that block password managers; paste blocked | 3.3.8 |
116
+ | | `REDUNDANT-ENTRY` | "Confirm / repeat" fields that make users re-type information | 3.3.7 |
117
+ | | `ERROR-SUGGESTION` | Error text that only says "required" without telling how to fix it | 3.3.1 / 3.3.3 |
118
+ | | `STATUS-LIVE` | Error / success message containers screen readers will not announce | 4.1.3 |
119
+ | **Keyboard and focus** | `TABINDEX` | Positive `tabindex`; `tabindex="-1"` on visible controls; `tabindex` on non-interactive elements | 2.4.3 |
120
+ | | `KEYBOARD` | Click handlers on `<div>` / `<span>` that a keyboard cannot use | 2.1.1 |
121
+ | | `FOCUS` | Focus outline removed with no replacement | 2.4.7 / 2.4.13 |
122
+ | | `FOCUS-ELEMENT` | Overlays / menus opened without moving focus (`.focus()` never called) | 2.4.3 |
123
+ | | `FOCUS-STRATEGY` | Sticky or fixed headers that can cover the focused element, no `scroll-padding-top` | 2.4.11 |
124
+ | | `TRAP` | Dialogs without `aria-modal`, overlays with no Escape-key handling | 2.1.2 / 2.4.3 |
125
+ | | `SHORTCUT` / `CHAR-KEYS` | `accesskey` and single-character keyboard shortcuts | 2.1.4 |
126
+ | | `MODALITY` | Content shown on hover only, `onmouseover` without a keyboard equivalent | 2.1.1 / 1.4.13 |
127
+ | **Touch and pointer** | `GESTURE` | Swipe / drag actions with no single-tap alternative | 2.5.1 / 2.5.7 |
128
+ | | `PTR-GESTURE` | Actions that fire on press (`mousedown` / `touchstart`) instead of release | 2.5.2 |
129
+ | **ARIA** | `ARIA` | Dialogs with no name, misspelled `aria-*` attributes, `aria-hidden` containers that hold focusable items | 4.1.2 |
130
+ | | `ARIA-ROLE` | Unknown or redundant ARIA roles, and roles missing the attributes they require | 4.1.2 |
131
+ | **Visual design (SCSS)** | `CONTRAST` | Text / background pairs under 4.5:1 (3:1 for large text); suggests the closest passing colour | 1.4.3 / 1.4.11 |
132
+ | | `COLOR` | Links told apart from text by colour only (underline removed) | 1.4.1 |
133
+ | | `SIZE` | Text smaller than 12px | 1.4.4 / 1.4.12 |
134
+ | | `SIZE-2.2` | Click / tap targets smaller than 24×24 px | 2.5.8 / 2.5.5 |
135
+ | | `ZOOM` | Text sized only in `vw`; viewport tag that blocks pinch-zoom | 1.4.4 |
136
+ | | `ORIENTATION` | Content hidden or rotated by orientation media queries | 1.3.4 |
137
+ | **Manual only** | `SENSORY` | Reminder to read content for "click the green button / on the right" instructions | 1.3.3 |
138
+ | | `CONSISTENT-HELP` | Reminder: help / contact link must be in the same place on every page | 3.2.6 |
139
+
140
+ The last two rules cannot be decided from source code, so they appear as reminders in the manual checklist at the end of every report.
93
141
 
94
142
  Notes
95
- - `HREF` = missing or empty href. `ERR-LINK` = dead links (`#`, `javascript:`) and unnamed or generic links.
96
- - `LABEL` also covers unnamed buttons and fieldsets.
97
- - CONTRAST only checks colours that appear together in one SCSS rule (literal values or `$variables`). Colours chosen in the CMS cannot be checked statically.
143
+ - `HREF` = missing or empty href. `ERR-LINK` = dead links and unnamed or generic links.
144
+ - `CONTRAST` only checks colours that appear together in one SCSS rule (literal values or `$variables`). Colours chosen in the CMS cannot be checked statically.
145
+ - Some rules (for example `TRAP` and `FOCUS-ELEMENT`) report as a low-priority **note** when the code appears to use a known library that handles the problem. Use `--all` to see notes.
146
+
147
+ ---
148
+
149
+ ## 4. What to expect
150
+
151
+ ### Output
152
+ This is a real run on two small files (`block/hero.html` and `sass/hero.scss`):
153
+
154
+ ```text
155
+ block/hero.html
156
+ 2:3 error ALT <img> has no alt attribute. WCAG 1.1.1
157
+ fix: Add alt="Describe the image" — or alt="" if purely decorative.
158
+ 3:20 error KEYBOARD <div> has a click handler but is not keyboard-operable. WCAG 2.1.1
159
+ fix: Use <button type="button"> (best). If impossible: role="button" tabindex="0" + Enter/Space key handler.
160
+ 4:6 warning ERR-LINK Link points to "#" (dead link / script action). WCAG 2.1.1 / 4.1.2
161
+ fix: If it navigates, use the real URL. If it runs JS, use <button type="button"> ...
162
+
163
+ sass/hero.scss
164
+ 1:1 error CONTRAST Contrast 2.85:1 for ".hero" (#999 on #fff); needs 4.5:1. WCAG 1.4.3
165
+ fix: Change the text colour to #747474 (closest passing shade), or change the background.
166
+
167
+ (manual checklist)
168
+ 1:1 manual KEYBOARD Tab through every page type once: order, visible focus, no traps ...
169
+
170
+ Scanned 2 files — 5 errors, 5 warnings, 7 manual checks
171
+
172
+ By rule:
173
+ ALT 1 err 0 warn 0 manual
174
+ ...
175
+ ```
176
+
177
+ How to read a line: `line:column severity RULE message WCAG number`, then `fix:` underneath.
178
+
179
+ ### Severity levels
180
+ | Level | Meaning | What to do |
181
+ |---|---|---|
182
+ | **error** | Definite failure of a WCAG criterion | Fix these first |
183
+ | **warning** | Likely a problem, but depends on context | Check each one, fix or silence with `a11y-ignore` |
184
+ | **manual** | The tool cannot decide | Do the check by hand (list at end of report) |
185
+ | **note** | Low priority hint (shown only with `--all`) | Optional |
186
+
187
+ ### Things to know
188
+ - **The first scan on an existing theme often shows many findings.** Many repeat the same cause (for example one SCSS rule used everywhere). Work through the "By rule" table from the top; fixing a shared template or mixin clears many lines at once.
189
+ - **Expect some warnings that do not apply.** The scanner reads source code, so it sometimes cannot tell that a library or the CMS already handles something. Silence those with `a11y-ignore` or `--disable`.
190
+ - **Line numbers point into your real files**, even when the line uses Galaxy syntax (`#$variable|x$#`, `{if="…"}`, `[[id]]`).
191
+ - **Exit code:** `1` if any **error** is found (so CI and pre-commit hooks can block), otherwise `0`. Change with `--fail-on warning` or `--fail-on none`.
192
+ - **`--html a11y-report.html`** writes a report you can filter by errors, warnings and manual checks and share with the team.
193
+ - **Zero findings does not mean "100% accessible".** See [Limits](#6-limits).
194
+
195
+ ---
196
+
197
+ ## 5. What a fix looks like
198
+
199
+ Every finding comes with the exact change to make. Typical examples:
200
+
201
+ **Missing alt text** (`ALT`, WCAG 1.1.1)
202
+ ```html
203
+ <!-- before --> <img src="team.jpg">
204
+ <!-- after --> <img src="team.jpg" alt="The support team at the 2026 summit">
205
+ <!-- decorative image --> <img src="divider.svg" alt="">
206
+ ```
207
+
208
+ **Clickable `<div>`** (`KEYBOARD`, WCAG 2.1.1)
209
+ ```html
210
+ <!-- before --> <div class="btn" onclick="openMenu()">Menu</div>
211
+ <!-- after --> <button type="button" class="btn" onclick="openMenu()">Menu</button>
212
+ ```
213
+
214
+ **Field with placeholder only** (`LABEL`, WCAG 1.3.1 / 3.3.2 / 4.1.2)
215
+ ```html
216
+ <!-- before --> <input type="email" name="email" placeholder="Email">
217
+ <!-- after --> <label for="email">Email</label>
218
+ <input id="email" type="email" name="email" autocomplete="email">
219
+ ```
220
+ (`autocomplete="email"` also fixes `INPUT-PURPOSE`.)
221
+
222
+ **Dead link used as a button** (`ERR-LINK`, WCAG 2.1.1 / 4.1.2)
223
+ ```html
224
+ <!-- before --> <a href="#" class="toggle">Open</a>
225
+ <!-- after --> <button type="button" class="toggle" aria-expanded="false" aria-controls="panel">Open</button>
226
+ <div id="panel" hidden>…</div>
227
+ ```
228
+
229
+ **Low contrast** (`CONTRAST`, WCAG 1.4.3). The scanner calculates the closest passing colour:
230
+ ```scss
231
+ // before
232
+ .hero { color: #999; background: #fff; } // 2.85:1, needs 4.5:1
233
+ // after
234
+ .hero { color: #747474; background: #fff; } // passes
235
+ ```
236
+
237
+ **Removed focus outline** (`FOCUS`, WCAG 2.4.7)
238
+ ```scss
239
+ // before
240
+ a:focus { outline: none; }
241
+ // after
242
+ a:focus-visible { outline: 2px solid $focus-color; outline-offset: 2px; }
243
+ ```
244
+
245
+ **Tiny click target** (`SIZE-2.2`, WCAG 2.5.8)
246
+ ```scss
247
+ // before
248
+ .btn { width: 18px; height: 18px; }
249
+ // after
250
+ .btn { min-width: 24px; min-height: 24px; } // ideally 44×44
251
+ ```
252
+
253
+ **Silence a finding that does not apply**
254
+ ```html
255
+ <!-- a11y-ignore: ALT -->
256
+ <img src="logo.svg" alt="">
257
+ ```
98
258
 
99
259
  ---
100
260
 
101
- ## 4. Limits
261
+ ## 6. Limits
102
262
 
103
263
  The scanner reads source code only. It cannot see:
104
264
  - colours and content that editors choose in the CMS,
@@ -113,7 +273,7 @@ No tool can promise "100% ADA". A realistic goal is: zero automated errors, warn
113
273
 
114
274
  ---
115
275
 
116
- ## 5. VS Code extension
276
+ ## 7. VS Code extension
117
277
 
118
278
  Prefer to see the problems while you edit? Install the **Galaxy A11y** extension from the VS Code Marketplace (publisher `shalii`). It runs this same scanner and shows the findings as squiggles, with the fix in the hover. It is a separate project: `galaxy-a11y-vscode`.
119
279
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shalii/galaxy-a11y",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Static WCAG 2.2 / ADA accessibility scanner for Galaxy CMS themes (html, scss, js)",
5
5
  "keywords": [
6
6
  "accessibility",