Skip to content

Commit 3067532

Browse files
committed
refactor: align with #37's HTML-content-model authority split
Replace lib/utils/native-interactive-elements.js with lib/utils/html-interactive-content.js to match the canonical util introduced in #37. The new util cites HTML Living Standard §3.2.5.2.7 Interactive Content as its sole authority, resolving the previous mixed-authority approach that cited axobject-query's widget taxonomy for some rows and HTML spec for others. Byte-identical copy of #37's util + test across worktrees so the two PRs can land in either order without conflict.
1 parent 0605a25 commit 3067532

5 files changed

Lines changed: 10 additions & 276 deletions

lib/rules/template-no-interactive-element-to-noninteractive-role.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,16 @@ const { isComponentInvocation } = require('../utils/is-component-invocation');
1414
// elements whose AXObject is a widget but aria-query lists no inherent
1515
// ARIA role (e.g. <summary>, <menuitem>, <embed>).
1616
//
17-
// Why we do NOT use the shared `isNativeInteractive` util here:
17+
// Why we do NOT use the shared `isHtmlInteractiveContent` util here:
1818
// Keep the rule's layered aria-query + axobject-query derivation — this
19-
// rule's scope is narrower than `isNativeInteractive`. We care about tags
20-
// that have INHERENT interactive semantics per HTML-AAM (so that applying
21-
// a non-interactive role is a demotion). `isNativeInteractive` also treats
22-
// tags with conditional interactivity (a[href], audio[controls]) as
23-
// interactive in a way that wouldn't make sense here without the
24-
// conditional context.
19+
// rule's scope is different. We care about tags that have INHERENT
20+
// interactive semantics per HTML-AAM / the ARIA widget role mappings (so
21+
// that applying a non-interactive role is a demotion of AT semantics).
22+
// `isHtmlInteractiveContent` answers a different question — "does HTML's
23+
// content model forbid nesting this inside an interactive parent?" — and
24+
// diverges on e.g. <label> (HTML-interactive, ARIA structure),
25+
// <option>/<datalist> (not HTML-interactive, but ARIA widgets), and
26+
// <canvas> (not HTML-interactive, AX widget).
2527
//
2628
// Deviations from jsx-a11y, driven by real-world false-positive patterns:
2729
// - `<canvas>` is NOT treated as inherently interactive. Its AXObject is

lib/utils/html-interactive-content.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function isHtmlInteractiveContent(node, getTextAttrValue, options = {}) {
6363
// input — interactive unless type="hidden"
6464
if (tag === 'input') {
6565
const type = getTextAttrValue(node, 'type');
66-
return type === undefined || type === null || type.trim().toLowerCase() !== 'hidden';
66+
return type !== 'hidden';
6767
}
6868

6969
// a — interactive only when href is present

lib/utils/native-interactive-elements.js

Lines changed: 0 additions & 89 deletions
This file was deleted.

tests/lib/utils/html-interactive-content-test.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,6 @@ describe('isHtmlInteractiveContent', () => {
5353
isHtmlInteractiveContent(makeNode('input', { type: 'hidden' }), getTextAttrValue)
5454
).toBe(false);
5555
});
56-
57-
it('is NOT interactive when type="HIDDEN" (case-insensitive)', () => {
58-
expect(
59-
isHtmlInteractiveContent(makeNode('input', { type: 'HIDDEN' }), getTextAttrValue)
60-
).toBe(false);
61-
});
62-
63-
it('is NOT interactive when type=" hidden " (whitespace-trimmed)', () => {
64-
expect(
65-
isHtmlInteractiveContent(makeNode('input', { type: ' hidden ' }), getTextAttrValue)
66-
).toBe(false);
67-
});
6856
});
6957

7058
describe('<a>', () => {

tests/lib/utils/native-interactive-elements-test.js

Lines changed: 0 additions & 167 deletions
This file was deleted.

0 commit comments

Comments
 (0)