param { ShadowRoot | HTMLElement } root param skipNode param isMatch param { number } maxDepth param { number } depth returns { HTMLElement [ ] } export function queryShadowRoot ( root , skipNode , isMatch , maxDepth = 20 , depth = 0 ) { let matches = [ ] ; if ( depth >= maxDepth ) { return matches ; } const traverseSlot = ( $slot ) => { const assignedNodes = $slot . assignedNodes ( ) . filter ( node => node . nodeType === 1 ) ; if ( assignedNodes . length > 0 ) { const $slotParent = assignedNodes [ 0 ] . parentElement ! ; return queryShadowRoot ( $slotParent , skipNode , isMatch , maxDepth , depth + 1 ) ; } return [ ] ; } ; const children = < HTMLElement [ ] > Array . from ( root . children || [ ] ) ; for ( const $child of children ) { if ( skipNode ( $child ) ) { continue ; } if ( isMatch ( $child ) ) { matches . push ( $child ) ; } if ( $child . shadowRoot != null ) { matches . push ( ... queryShadowRoot ( $child . shadowRoot , skipNode , isMatch , maxDepth , depth + 1 ) ) ; } else if ( $child . tagName === "SLOT" ) { matches . push ( ... traverseSlot ( < HTMLSlotElement > $child ) ) ; } else { matches . push ( ... queryShadowRoot ( $child , skipNode , isMatch , maxDepth , depth + 1 ) ) ; } } return matches ; }