pour-engine 1.7.0 → 1.8.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.
package/config/project.config.js
CHANGED
package/engine/lib/roles.js
CHANGED
|
@@ -150,6 +150,15 @@ export function implicitRole(element) {
|
|
|
150
150
|
if (tag === 'img') return element.getAttribute('alt') === '' ? 'presentation' : 'img';
|
|
151
151
|
if (tag === 'header') return element.closest('article, aside, main, nav, section') ? 'generic' : 'banner';
|
|
152
152
|
if (tag === 'footer') return element.closest('article, aside, main, nav, section') ? 'generic' : 'contentinfo';
|
|
153
|
+
// HTML-AAM: an aside inside sectioning content is complementary only when
|
|
154
|
+
// it carries an accessible name; unnamed it is generic. Verified against
|
|
155
|
+
// Chromium's accessibility tree, which demotes exactly that case and keeps
|
|
156
|
+
// a top-level aside complementary whether named or not.
|
|
157
|
+
if (tag === 'aside') {
|
|
158
|
+
const sectioned = element.parentElement?.closest('article, aside, nav, section');
|
|
159
|
+
const named = element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby');
|
|
160
|
+
return sectioned && !named ? 'generic' : 'complementary';
|
|
161
|
+
}
|
|
153
162
|
if (tag === 'section') {
|
|
154
163
|
return element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby') ? 'region' : 'generic';
|
|
155
164
|
}
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
// WCAG SC 4.1.2 Name, Role, Value (Level A)
|
|
2
|
-
// ARIA
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// An ARIA attribute the role does not support is INERT. Measured in Chromium:
|
|
3
|
+
// aria-expanded on a button exposes expanded=false, and the same attribute on
|
|
4
|
+
// a complementary landmark exposes no state at all. It is dropped, not
|
|
5
|
+
// misreported, so the old "announces the wrong state" wording was wrong.
|
|
6
|
+
//
|
|
7
|
+
// Which is why this REVIEWS rather than fails. ARIA 1.2 §5.2.3 says authors
|
|
8
|
+
// MAY provide supported states and user agents MUST map them; "prohibited"
|
|
9
|
+
// (§5.2.5) is a separate category this rule does not cover. An unsupported
|
|
10
|
+
// attribute is therefore not a spec violation, and name, role and value are
|
|
11
|
+
// all still conveyed correctly, so no success criterion provably fails.
|
|
12
|
+
//
|
|
13
|
+
// The 4.1.2 tag stays because there IS a real failure hiding here: if the
|
|
14
|
+
// element genuinely has the state the author was reaching for, that state is
|
|
15
|
+
// now invisible to assistive technology. Whether it does is exactly what the
|
|
16
|
+
// DOM cannot establish, so it is a question for a person. Same reasoning that
|
|
17
|
+
// put aria-label-misuse in best-practice.
|
|
18
|
+
//
|
|
19
|
+
// Worth knowing when comparing against other tools: aria-expanded WAS
|
|
20
|
+
// inherited into complementary, banner, heading, img and list under ARIA 1.1,
|
|
21
|
+
// and was narrowed in 1.2 (narrowed again in the 1.3 draft). Markup written
|
|
22
|
+
// against 1.1 is not conforming under 1.2, and a tool on the older baseline
|
|
23
|
+
// stays silent on it.
|
|
5
24
|
import { GLOBAL_ARIA, ROLE_ARIA, KNOWN_ARIA, effectiveRole } from '../../lib/roles.js';
|
|
6
25
|
|
|
7
26
|
// aria-label/labelledby misuse on generic elements has its own rule
|
|
@@ -10,7 +29,7 @@ const HANDLED_ELSEWHERE = new Set(['label', 'labelledby']);
|
|
|
10
29
|
|
|
11
30
|
export default {
|
|
12
31
|
id: 'aria-allowed-attr',
|
|
13
|
-
impact: '
|
|
32
|
+
impact: 'moderate',
|
|
14
33
|
tags: ['wcag2a', 'wcag412'],
|
|
15
34
|
help: 'ARIA attributes must be allowed for the element’s role',
|
|
16
35
|
helpUrl: 'https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html',
|
|
@@ -35,10 +54,11 @@ export default {
|
|
|
35
54
|
|
|
36
55
|
const disallowed = ariaAttrs.filter((name) => !GLOBAL_ARIA.has(name) && !allowed.includes(name));
|
|
37
56
|
if (!disallowed.length) return { status: 'pass' };
|
|
57
|
+
const names = disallowed.map((n) => `aria-${n}`);
|
|
38
58
|
return {
|
|
39
|
-
status: '
|
|
40
|
-
message: `${
|
|
41
|
-
fix: `
|
|
59
|
+
status: 'incomplete',
|
|
60
|
+
message: `${names.join(', ')} is not supported on role "${role}", so the browser drops it and assistive technology never sees it. Nothing is announced wrongly, but nothing is announced at all. If this element really does have that state, it is currently invisible: check whether it needs conveying another way.`,
|
|
61
|
+
fix: `Move ${names.join('/')} to the element whose role supports it, usually the control that toggles this one, or remove it if the element has no such state.`,
|
|
42
62
|
};
|
|
43
63
|
},
|
|
44
64
|
};
|
package/package.json
CHANGED