Skip to content

Commit 4cf8340

Browse files
committed
Add rules no-interactive-element-to-noninteractive-role and no-noninteractive-element-to-interactive-role
1 parent 0f03fb4 commit 4cf8340

7 files changed

+951
-0
lines changed

__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js

Lines changed: 358 additions & 0 deletions
Large diffs are not rendered by default.

__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js

Lines changed: 425 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# no-interactive-element-to-noninteractive-role
2+
3+
Write a useful explanation here!
4+
5+
#### References
6+
1.
7+
8+
## Rule details
9+
10+
This rule takes no arguments.
11+
12+
### Succeed
13+
```jsx
14+
<div />
15+
```
16+
17+
### Fail
18+
```jsx
19+
20+
```
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# no-noninteractive-element-to-interactive-role
2+
3+
Write a useful explanation here!
4+
5+
#### References
6+
1.
7+
8+
## Rule details
9+
10+
This rule takes no arguments.
11+
12+
### Succeed
13+
```jsx
14+
<div />
15+
```
16+
17+
### Fail
18+
```jsx
19+
20+
```

src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ module.exports = {
2222
'no-access-key': require('./rules/no-access-key'),
2323
'no-autofocus': require('./rules/no-autofocus'),
2424
'no-distracting-elements': require('./rules/no-distracting-elements'),
25+
'no-interactive-element-to-noninteractive-role': require('./rules/no-interactive-element-to-noninteractive-role'),
2526
'no-noninteractive-element-interactions': require('./rules/no-noninteractive-element-interactions'),
27+
'no-noninteractive-element-to-interactive-role': require('./rules/no-noninteractive-element-to-interactive-role'),
2628
'no-onchange': require('./rules/no-onchange'),
2729
'no-redundant-roles': require('./rules/no-redundant-roles'),
2830
'no-static-element-interactions': require('./rules/no-static-element-interactions'),
@@ -60,7 +62,9 @@ module.exports = {
6062
'jsx-a11y/no-access-key': 'error',
6163
'jsx-a11y/no-autofocus': 'error',
6264
'jsx-a11y/no-distracting-elements': 'error',
65+
'jsx-a11y/no-interactive-element-to-noninteractive-role': 'error',
6366
'jsx-a11y/no-noninteractive-element-interactions': 'error',
67+
'jsx-a11y/no-noninteractive-element-to-interactive-role': 'error',
6468
'jsx-a11y/no-onchange': 'error',
6569
'jsx-a11y/no-redundant-roles': 'error',
6670
'jsx-a11y/no-static-element-interactions': 'warn',
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @fileoverview Disallow inherently interactive elements to be assigned
3+
* non-interactive roles.
4+
* @author Jesse Beach
5+
* @flow
6+
*/
7+
8+
// ----------------------------------------------------------------------------
9+
// Rule Definition
10+
// ----------------------------------------------------------------------------
11+
12+
import {
13+
dom,
14+
} from 'aria-query';
15+
import {
16+
elementType,
17+
} from 'jsx-ast-utils';
18+
import type { JSXOpeningElement } from 'ast-types-flow';
19+
import { generateObjSchema } from '../util/schemas';
20+
import isInteractiveElement from '../util/isInteractiveElement';
21+
import isNonInteractiveRole from '../util/isNonInteractiveRole';
22+
import isPresentationRole from '../util/isPresentationRole';
23+
24+
const errorMessage =
25+
'Interactive elements should not be assigned non-interactive roles';
26+
27+
const schema = generateObjSchema();
28+
29+
const domElements = [...dom.keys()];
30+
31+
module.exports = {
32+
meta: {
33+
docs: {},
34+
schema: [schema],
35+
},
36+
37+
create: (context: ESLintContext) => ({
38+
JSXOpeningElement: (
39+
node: JSXOpeningElement,
40+
) => {
41+
const attributes = node.attributes;
42+
const type = elementType(node);
43+
44+
if (!domElements.includes(type)) {
45+
// Do not test higher level JSX components, as we do not know what
46+
// low-level DOM element this maps to.
47+
return;
48+
}
49+
if (
50+
isInteractiveElement(type, attributes)
51+
&& (
52+
isNonInteractiveRole(type, attributes)
53+
|| isPresentationRole(type, attributes)
54+
)
55+
) {
56+
// Visible, non-interactive elements should not have an interactive handler.
57+
context.report({
58+
node,
59+
message: errorMessage,
60+
});
61+
}
62+
},
63+
}),
64+
};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @fileoverview Disallow inherently non-interactive elements to be assigned
3+
* interactive roles.
4+
* @author Jesse Beach
5+
* @flow
6+
*/
7+
8+
// ----------------------------------------------------------------------------
9+
// Rule Definition
10+
// ----------------------------------------------------------------------------
11+
12+
import {
13+
dom,
14+
} from 'aria-query';
15+
import {
16+
elementType,
17+
} from 'jsx-ast-utils';
18+
import type { JSXOpeningElement } from 'ast-types-flow';
19+
import { generateObjSchema } from '../util/schemas';
20+
import isNonInteractiveElement from '../util/isNonInteractiveElement';
21+
import isInteractiveRole from '../util/isInteractiveRole';
22+
23+
const errorMessage =
24+
'Non-interactive elements should not be assigned interactive roles';
25+
26+
const schema = generateObjSchema();
27+
28+
const domElements = [...dom.keys()];
29+
30+
module.exports = {
31+
meta: {
32+
docs: {},
33+
schema: [schema],
34+
},
35+
36+
create: (context: ESLintContext) => ({
37+
JSXOpeningElement: (
38+
node: JSXOpeningElement,
39+
) => {
40+
const attributes = node.attributes;
41+
const type = elementType(node);
42+
43+
if (!domElements.includes(type)) {
44+
// Do not test higher level JSX components, as we do not know what
45+
// low-level DOM element this maps to.
46+
return;
47+
}
48+
if (
49+
isNonInteractiveElement(type, attributes)
50+
&& isInteractiveRole(type, attributes)
51+
) {
52+
// Visible, non-interactive elements should not have an interactive handler.
53+
context.report({
54+
node,
55+
message: errorMessage,
56+
});
57+
}
58+
},
59+
}),
60+
};

0 commit comments

Comments
 (0)