-
-
Notifications
You must be signed in to change notification settings - Fork 208
/
get-interactive-element-role-schemas.ts
52 lines (47 loc) · 1.91 KB
/
get-interactive-element-role-schemas.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import type {
ARIARoleDefinitionKey,
ARIARoleRelationConcept,
} from 'aria-query';
import { elementRoles, roles } from 'aria-query';
let interactiveElementRoleSchemas: ARIARoleRelationConcept[] | null = null;
// This function follows the lazy initialization pattern.
// Since this is a top-level module (it will be included via `require`), we do not need to
// initialize the `interactiveElementRoleSchemas` until the function is called
// for the first time, so we will not take up the memory.
export function getInteractiveElementRoleSchemas(): ARIARoleRelationConcept[] {
if (interactiveElementRoleSchemas === null) {
const roleKeys = [...roles.keys()];
const elementRoleEntries = [...elementRoles.entries()];
// This set will contain all possible values for the `role` attribute,
// e.g. `button`, `navigation` or `presentation`.
const interactiveRoles = new Set<ARIARoleDefinitionKey>(
roleKeys
.filter((name: ARIARoleDefinitionKey) => {
const role = roles.get(name);
return (
role &&
!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',
),
);
interactiveElementRoleSchemas = elementRoleEntries.reduce<
ARIARoleRelationConcept[]
>((accumulator, [elementSchema, roleSet]) => {
return accumulator.concat(
[...roleSet].every((role) => interactiveRoles.has(role))
? elementSchema
: [],
);
}, []);
}
return interactiveElementRoleSchemas;
}