Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] Update A11y no noninteractive element with positive tabindex warning to ignore tabpanel role. #8025

Merged
merged 2 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 5 additions & 20 deletions src/compiler/compile/utils/a11y.ts
Expand Up @@ -7,17 +7,17 @@ import {
import { AXObjects, AXObjectRoles, elementAXObjects } from 'axobject-query';
import Attribute from '../nodes/Attribute';

const roles = [...roles_map.keys()];
const non_abstract_roles = [...roles_map.keys()].filter((name) => !roles_map.get(name).abstract);

const non_interactive_roles = new Set(
roles
non_abstract_roles
.filter((name) => {
const role = roles_map.get(name);
return (
!roles_map.get(name).abstract &&
// 'toolbar' does not descend from widget, but it does support
// aria-activedescendant, thus in practice we treat it as a widget.
name !== 'toolbar' &&
// focusable tabpanel elements are recommended if any panels in a set contain content where the first element in the panel is not focusable.
!['toolbar', 'tabpanel'].includes(name) &&
!role.superClass.some((classes) => classes.includes('widget'))
);
})
Expand All @@ -29,22 +29,7 @@ const non_interactive_roles = new Set(
);

const interactive_roles = new Set(
roles
.filter((name) => {
const role = roles_map.get(name);
return (
!role.abstract &&
// The `progressbar` is descended from `widget`, but in practice, its
// value is always `readonly`, so we treat it as a non-interactive role.
name !== 'progressbar' &&
role.superClass.some((classes) => classes.includes('widget'))
);
})
.concat(
// 'toolbar' does not descend from widget, but it does support
// aria-activedescendant, thus in practice we treat it as a widget.
'toolbar'
)
non_abstract_roles.filter((name) => !non_interactive_roles.has(name))
);

export function is_non_interactive_roles(role: ARIARoleDefintionKey) {
Expand Down
Expand Up @@ -7,6 +7,7 @@
<div role='button' tabindex='0' />
<div role='article' tabindex='-1' />
<article tabindex='-1' />
<div role="tabpanel" tabindex='0' />
<!-- invalid -->
<div tabindex='0' />
<div role='article' tabindex='0' />
Expand Down
40 changes: 20 additions & 20 deletions test/validator/samples/a11y-no-nointeractive-tabindex/warnings.json
Expand Up @@ -2,61 +2,61 @@
{
"code": "a11y-no-noninteractive-tabindex",
"end": {
"character": 241,
"character": 278,
"column": 20,
"line": 11
"line": 12
},
"message": "A11y: noninteractive element cannot have positive tabIndex value",
"pos": 221,
"pos": 258,
"start": {
"character": 221,
"character": 258,
"column": 0,
"line": 11
"line": 12
}
},
{
"code": "a11y-no-noninteractive-tabindex",
"end": {
"character": 277,
"character": 314,
"column": 35,
"line": 12
"line": 13
},
"message": "A11y: noninteractive element cannot have positive tabIndex value",
"pos": 242,
"pos": 279,
"start": {
"character": 242,
"character": 279,
"column": 0,
"line": 12
"line": 13
}
},
{
"code": "a11y-no-noninteractive-tabindex",
"end": {
"character": 302,
"character": 339,
"column": 24,
"line": 13
"line": 14
},
"message": "A11y: noninteractive element cannot have positive tabIndex value",
"pos": 278,
"pos": 315,
"start": {
"character": 278,
"character": 315,
"column": 0,
"line": 13
"line": 14
}
},
{
"code": "a11y-no-noninteractive-tabindex",
"end": {
"character": 329,
"character": 366,
"column": 26,
"line": 14
"line": 15
},
"message": "A11y: noninteractive element cannot have positive tabIndex value",
"pos": 303,
"pos": 340,
"start": {
"character": 303,
"character": 340,
"column": 0,
"line": 14
"line": 15
}
}
]