1616
1717import type { SelectorEngine , SelectorRoot } from './selectorEngine' ;
1818import { matchesAttributePart } from './selectorUtils' ;
19- import { beginAriaCaches , endAriaCaches , getAriaChecked , getAriaDisabled , getAriaExpanded , getAriaLevel , getAriaPressed , getAriaSelected , getElementAccessibleName , getElementsByRole , isElementHiddenForAria , kAriaCheckedRoles , kAriaExpandedRoles , kAriaLevelRoles , kAriaPressedRoles , kAriaSelectedRoles } from './roleUtils' ;
19+ import { beginAriaCaches , endAriaCaches , getAriaChecked , getAriaDisabled , getAriaExpanded , getAriaLevel , getAriaPressed , getAriaRole , getAriaSelected , getElementAccessibleName , isElementHiddenForAria , kAriaCheckedRoles , kAriaExpandedRoles , kAriaLevelRoles , kAriaPressedRoles , kAriaSelectedRoles } from './roleUtils' ;
2020import { parseAttributeSelector , type AttributeSelectorPart , type AttributeSelectorOperator } from '../../utils/isomorphic/selectorParser' ;
2121import { normalizeWhiteSpace } from '../../utils/isomorphic/stringUtils' ;
22- import { isInsideScope } from './domUtils' ;
2322
2423type RoleEngineOptions = {
2524 role : string ;
@@ -126,27 +125,26 @@ function validateAttributes(attrs: AttributeSelectorPart[], role: string): RoleE
126125}
127126
128127function queryRole ( scope : SelectorRoot , options : RoleEngineOptions , internal : boolean ) : Element [ ] {
129- const doc = scope . nodeType === 9 /* Node.DOCUMENT_NODE */ ? scope as Document : scope . ownerDocument ;
130- const elements = doc ? getElementsByRole ( doc , options . role ) : [ ] ;
131- return elements . filter ( element => {
132- if ( ! isInsideScope ( scope , element ) )
133- return false ;
128+ const result : Element [ ] = [ ] ;
129+ const match = ( element : Element ) => {
130+ if ( getAriaRole ( element ) !== options . role )
131+ return ;
134132 if ( options . selected !== undefined && getAriaSelected ( element ) !== options . selected )
135- return false ;
133+ return ;
136134 if ( options . checked !== undefined && getAriaChecked ( element ) !== options . checked )
137- return false ;
135+ return ;
138136 if ( options . pressed !== undefined && getAriaPressed ( element ) !== options . pressed )
139- return false ;
137+ return ;
140138 if ( options . expanded !== undefined && getAriaExpanded ( element ) !== options . expanded )
141- return false ;
139+ return ;
142140 if ( options . level !== undefined && getAriaLevel ( element ) !== options . level )
143- return false ;
141+ return ;
144142 if ( options . disabled !== undefined && getAriaDisabled ( element ) !== options . disabled )
145- return false ;
143+ return ;
146144 if ( ! options . includeHidden ) {
147145 const isHidden = isElementHiddenForAria ( element ) ;
148146 if ( isHidden )
149- return false ;
147+ return ;
150148 }
151149 if ( options . name !== undefined ) {
152150 // Always normalize whitespace in the accessible name.
@@ -157,10 +155,25 @@ function queryRole(scope: SelectorRoot, options: RoleEngineOptions, internal: bo
157155 if ( internal && ! options . exact && options . nameOp === '=' )
158156 options . nameOp = '*=' ;
159157 if ( ! matchesAttributePart ( accessibleName , { name : '' , jsonPath : [ ] , op : options . nameOp || '=' , value : options . name , caseSensitive : ! ! options . exact } ) )
160- return false ;
158+ return ;
161159 }
162- return true ;
163- } ) ;
160+ result . push ( element ) ;
161+ } ;
162+
163+ const query = ( root : Element | ShadowRoot | Document ) => {
164+ const shadows : ShadowRoot [ ] = [ ] ;
165+ if ( ( root as Element ) . shadowRoot )
166+ shadows . push ( ( root as Element ) . shadowRoot ! ) ;
167+ for ( const element of root . querySelectorAll ( '*' ) ) {
168+ match ( element ) ;
169+ if ( element . shadowRoot )
170+ shadows . push ( element . shadowRoot ) ;
171+ }
172+ shadows . forEach ( query ) ;
173+ } ;
174+
175+ query ( scope ) ;
176+ return result ;
164177}
165178
166179export function createRoleEngine ( internal : boolean ) : SelectorEngine {
0 commit comments