@@ -11,19 +11,22 @@ import {
11
11
AXObjects ,
12
12
elementAXObjects ,
13
13
} from 'axobject-query' ;
14
- import {
15
- getLiteralPropValue ,
16
- propName ,
17
- } from 'jsx-ast-utils' ;
14
+ import attributesComparator from './attributesComparator' ;
18
15
19
16
const roleKeys = [ ...roles . keys ( ) ] ;
17
+ const elementRoleEntries = [ ...elementRoles ] ;
20
18
21
19
const nonInteractiveRoles = new Set (
22
20
roleKeys
23
- . filter ( name => ! roles . get ( name ) . abstract )
24
- . filter ( name => ! roles . get ( name ) . superClass . some (
25
- klasses => klasses . includes ( 'widget' ) ) ,
26
- ) ,
21
+ . filter ( ( name ) => {
22
+ const role = roles . get ( name ) ;
23
+ return (
24
+ ! role . abstract
25
+ && ! role . superClass . some (
26
+ classes => classes . includes ( 'widget' ) ,
27
+ )
28
+ ) ;
29
+ } ) ,
27
30
) ;
28
31
29
32
const interactiveRoles = new Set (
@@ -33,120 +36,97 @@ const interactiveRoles = new Set(
33
36
// aria-activedescendant, thus in practice we treat it as a widget.
34
37
'toolbar' ,
35
38
)
36
- . filter ( name => ! roles . get ( name ) . abstract )
37
- . filter ( name => roles . get ( name ) . superClass . some (
38
- klasses => klasses . includes ( 'widget' ) ) ,
39
- ) ,
39
+ . filter ( ( name ) => {
40
+ const role = roles . get ( name ) ;
41
+ return (
42
+ ! role . abstract
43
+ && role . superClass . some (
44
+ classes => classes . includes ( 'widget' ) ,
45
+ )
46
+ ) ;
47
+ } ) ,
40
48
) ;
41
49
42
50
43
- const nonInteractiveElementRoles = [ ... elementRoles . entries ( ) ]
51
+ const nonInteractiveElementRoleSchemas = elementRoleEntries
44
52
. reduce ( (
45
53
accumulator ,
46
54
[
47
55
elementSchema ,
48
56
roleSet ,
49
57
] ,
50
58
) => {
51
- if ( [ ...roleSet . keys ( ) ] . every (
59
+ if ( [ ...roleSet ] . every (
52
60
( role ) : boolean => nonInteractiveRoles . has ( role ) ,
53
61
) ) {
54
- accumulator . set ( elementSchema , roleSet ) ;
62
+ accumulator . push ( elementSchema ) ;
55
63
}
56
64
return accumulator ;
57
- } , new Map ( [ ] ) ) ;
65
+ } , [ ] ) ;
58
66
59
- const interactiveElementRoles = [ ... elementRoles . entries ( ) ]
67
+ const interactiveElementRoleSchemas = elementRoleEntries
60
68
. reduce ( (
61
69
accumulator ,
62
70
[
63
71
elementSchema ,
64
72
roleSet ,
65
73
] ,
66
74
) => {
67
- if ( [ ...roleSet . keys ( ) ] . some (
75
+ if ( [ ...roleSet ] . some (
68
76
( role ) : boolean => interactiveRoles . has ( role ) ,
69
77
) ) {
70
- accumulator . set ( elementSchema , roleSet ) ;
78
+ accumulator . push ( elementSchema ) ;
71
79
}
72
80
return accumulator ;
73
- } , new Map ( [ ] ) ) ;
81
+ } , [ ] ) ;
74
82
75
83
const interactiveAXObjects = new Set (
76
84
[ ...AXObjects . keys ( ) ]
77
- . filter ( name => [ 'widget' ] . includes ( AXObjects . get ( name ) . type ) ) ,
85
+ . filter ( name => AXObjects . get ( name ) . type === 'widget' ) ,
78
86
) ;
79
87
80
- const interactiveElementAXObjects = [ ...elementAXObjects . entries ( ) ]
88
+ const interactiveElementAXObjectSchemas = [ ...elementAXObjects ]
81
89
. reduce ( (
82
90
accumulator ,
83
91
[
84
92
elementSchema ,
85
93
AXObjectSet ,
86
94
] ,
87
95
) => {
88
- if ( [ ...AXObjectSet . keys ( ) ] . every (
96
+ if ( [ ...AXObjectSet ] . every (
89
97
( role ) : boolean => interactiveAXObjects . has ( role ) ,
90
98
) ) {
91
- accumulator . set ( elementSchema , AXObjectSet ) ;
99
+ accumulator . push ( elementSchema ) ;
92
100
}
93
101
return accumulator ;
94
- } , new Map ( [ ] ) ) ;
95
-
96
- function attributesComparator ( baseAttributes = [ ] , attributes = [ ] ) : boolean {
97
- return baseAttributes . every (
98
- ( baseAttr ) : boolean => attributes . some (
99
- ( attribute ) : boolean => {
100
- // Guard against non-JSXAttribute nodes like JSXSpreadAttribute
101
- if ( attribute . type !== 'JSXAttribute' ) {
102
- return false ;
103
- }
104
- let attrMatches = false ;
105
- let valueMatches = true ;
106
- // Attribute matches.
107
- if ( baseAttr . name === propName ( attribute ) . toLowerCase ( ) ) {
108
- attrMatches = true ;
109
- }
110
- // Value exists and matches.
111
- if ( baseAttr . value ) {
112
- valueMatches = baseAttr . value === getLiteralPropValue ( attribute ) ;
113
- }
114
- return attrMatches && valueMatches ;
115
- } ,
116
- ) ,
117
- ) ;
118
- }
102
+ } , [ ] ) ;
119
103
120
104
function checkIsInteractiveElement ( tagName , attributes ) : boolean {
121
- // Check in configuration for an override.
122
-
123
- // Check in elementRoles for inherent interactive role associations for
124
- // this element.
125
- for ( const [ elementSchema ] of interactiveElementRoles ) {
126
- if (
105
+ function elementSchemaMatcher ( elementSchema ) {
106
+ return (
127
107
tagName === elementSchema . name
128
108
&& attributesComparator ( elementSchema . attributes , attributes )
129
- ) {
130
- return true ;
131
- }
109
+ ) ;
132
110
}
133
-
134
111
// Check in elementRoles for inherent interactive role associations for
135
112
// this element.
136
- for ( const [ elementSchema ] of nonInteractiveElementRoles ) {
137
- if (
138
- tagName === elementSchema . name
139
- && attributesComparator ( elementSchema . attributes , attributes )
140
- ) {
141
- return false ;
142
- }
113
+ const isInherentInteractiveElement = interactiveElementRoleSchemas
114
+ . some ( elementSchemaMatcher ) ;
115
+ if ( isInherentInteractiveElement ) {
116
+ return true ;
143
117
}
144
-
145
- // Check in elementAXObjects for AX Tree associations for this elements.
146
- for ( const [ elementSchema ] of interactiveElementAXObjects ) {
147
- if ( tagName === elementSchema . name ) {
148
- return attributesComparator ( elementSchema . attributes , attributes ) ;
149
- }
118
+ // Check in elementRoles for inherent non-interactive role associations for
119
+ // this element.
120
+ const isInherentNonInteractiveElement = nonInteractiveElementRoleSchemas
121
+ . some ( elementSchemaMatcher ) ;
122
+ if ( isInherentNonInteractiveElement ) {
123
+ return false ;
124
+ }
125
+ // Check in elementAXObjects for AX Tree associations for this element.
126
+ const isInteractiveAXElement = interactiveElementAXObjectSchemas
127
+ . some ( elementSchemaMatcher ) ;
128
+ if ( isInteractiveAXElement ) {
129
+ return true ;
150
130
}
151
131
152
132
return false ;
0 commit comments