@@ -14,6 +14,7 @@ import {
14
14
import includes from 'array-includes' ;
15
15
import flatMap from 'array.prototype.flatmap' ;
16
16
17
+ import { getProp , getPropValue } from 'jsx-ast-utils' ;
17
18
import attributesComparator from './attributesComparator' ;
18
19
19
20
const roleKeys = roles . keys ( ) ;
@@ -68,14 +69,50 @@ const interactiveElementAXObjectSchemas = flatMap(
68
69
( [ elementSchema , AXObjectsArr ] ) => ( AXObjectsArr . every ( ( role ) : boolean => interactiveAXObjects . has ( role ) ) ? [ elementSchema ] : [ ] ) ,
69
70
) ;
70
71
71
- function checkIsInteractiveElement ( tagName , attributes ) : boolean {
72
+ function checkIsInteractiveElement ( tagName , attributes , options = { } ) : boolean {
72
73
function elementSchemaMatcher ( elementSchema ) {
73
74
return (
74
75
tagName === elementSchema . name
75
76
&& attributesComparator ( elementSchema . attributes , attributes )
76
77
) ;
77
78
}
78
79
80
+ function isInteractiveElementWithCustomOptions ( ) {
81
+ const elementConfig = options [ tagName ] ;
82
+
83
+ if ( ! elementConfig ) return false ;
84
+
85
+ return Object . keys ( elementConfig . attributes ) . some ( ( standardAttr ) => {
86
+ const customAttrs = elementConfig . attributes [ standardAttr ] ;
87
+
88
+ const validCustomAttr = customAttrs . find ( ( customAttr ) => {
89
+ if ( customAttr === standardAttr ) return false ;
90
+ const customProp = getProp ( attributes , customAttr ) ;
91
+ return customProp && getPropValue ( customProp ) != null ;
92
+ } ) ;
93
+
94
+ if ( validCustomAttr ) {
95
+ const originalProp = getProp ( attributes , validCustomAttr ) ;
96
+ const standardProp = {
97
+ ...originalProp ,
98
+ name : {
99
+ ...originalProp . name ,
100
+ name : standardAttr ,
101
+ } ,
102
+ } ;
103
+
104
+ return checkIsInteractiveElement ( tagName , [ ...attributes , standardProp ] , { } ) ;
105
+ }
106
+
107
+ return false ;
108
+ } ) ;
109
+ }
110
+
111
+ // Checks if there are custom options for this element
112
+ if ( options && Object . keys ( options ) . length > 0 ) {
113
+ return isInteractiveElementWithCustomOptions ( ) ;
114
+ }
115
+
79
116
// Check in elementRoles for inherent interactive role associations for
80
117
// this element.
81
118
const isInherentInteractiveElement = interactiveElementRoleSchemas . some ( elementSchemaMatcher ) ;
@@ -106,14 +143,15 @@ function checkIsInteractiveElement(tagName, attributes): boolean {
106
143
const isInteractiveElement = (
107
144
tagName : string ,
108
145
attributes : Array < Node > ,
146
+ options : Object = { } ,
109
147
) : boolean => {
110
148
// Do not test higher level JSX components, as we do not know what
111
149
// low-level DOM element this maps to.
112
150
if ( ! dom . has ( tagName ) ) {
113
151
return false ;
114
152
}
115
153
116
- return checkIsInteractiveElement ( tagName , attributes ) ;
154
+ return checkIsInteractiveElement ( tagName , attributes , options ) ;
117
155
} ;
118
156
119
157
export default isInteractiveElement ;
0 commit comments