@@ -2208,6 +2208,7 @@ export function readPageActionState(
22082208 const roots : ParentNode [ ] = observationRoot ? [ observationRoot ] : [ ]
22092209 const allElements : Element [ ] = [ ]
22102210 const stateNodeCap = 12_000
2211+ const overlayLimit = 10
22112212 for ( let index = 0 ; index < roots . length ; index ++ ) {
22122213 for ( const element of Array . from ( roots [ index ] . querySelectorAll ( '*' ) ) ) {
22132214 if ( allElements . length >= stateNodeCap ) break
@@ -2296,56 +2297,54 @@ export function readPageActionState(
22962297 const dialogs = allElements . filter ( ( element ) =>
22972298 element . matches ( 'dialog[open], [role="dialog"], [aria-modal="true"]' )
22982299 )
2299- const visibleDialogLabels = dialogs
2300- . filter ( ( element ) => {
2301- const rect = element . getBoundingClientRect ( )
2302- const view = element . ownerDocument . defaultView
2303- if ( ! view || rect . width <= 0 || rect . height <= 0 ) return false
2304- for ( let current : Element | null = element ; current ; ) {
2305- const style = view . getComputedStyle ( current )
2306- if (
2307- style . display === 'none' ||
2308- style . visibility === 'hidden' ||
2309- Number . parseFloat ( style . opacity || '1' ) <= 0.01 ||
2310- current . hasAttribute ( 'hidden' ) ||
2311- current . getAttribute ( 'aria-hidden' ) === 'true'
2312- ) {
2313- return false
2314- }
2315- if ( current . parentElement ) current = current . parentElement
2316- else {
2317- const root = current . getRootNode ( )
2318- current = 'host' in root ? ( root . host as Element ) : null
2319- }
2300+ const visibleDialogs = dialogs . filter ( ( element ) => {
2301+ const rect = element . getBoundingClientRect ( )
2302+ const view = element . ownerDocument . defaultView
2303+ if ( ! view || rect . width <= 0 || rect . height <= 0 ) return false
2304+ for ( let current : Element | null = element ; current ; ) {
2305+ const style = view . getComputedStyle ( current )
2306+ if (
2307+ style . display === 'none' ||
2308+ style . visibility === 'hidden' ||
2309+ Number . parseFloat ( style . opacity || '1' ) <= 0.01 ||
2310+ current . hasAttribute ( 'hidden' ) ||
2311+ current . getAttribute ( 'aria-hidden' ) === 'true'
2312+ ) {
2313+ return false
23202314 }
2321- return (
2322- rect . right > 0 &&
2323- rect . bottom > 0 &&
2324- rect . left < view . innerWidth &&
2325- rect . top < view . innerHeight
2326- )
2327- } )
2328- . slice ( 0 , 10 )
2329- . map ( ( element ) =>
2330- (
2331- element . getAttribute ( 'aria-label' ) ||
2332- ( element as HTMLElement ) . innerText ||
2333- element . textContent ||
2334- ''
2335- )
2336- . replace ( / \s + / g, ' ' )
2337- . trim ( )
2338- . slice ( 0 , 120 )
2339- . replace ( / [ \uD800 - \uDBFF ] $ / , '' )
2315+ if ( current . parentElement ) current = current . parentElement
2316+ else {
2317+ const root = current . getRootNode ( )
2318+ current = 'host' in root ? ( root . host as Element ) : null
2319+ }
2320+ }
2321+ return (
2322+ rect . right > 0 &&
2323+ rect . bottom > 0 &&
2324+ rect . left < view . innerWidth &&
2325+ rect . top < view . innerHeight
23402326 )
2327+ } )
2328+ const visibleDialogLabels = visibleDialogs . slice ( 0 , overlayLimit ) . map ( ( element ) =>
2329+ (
2330+ element . getAttribute ( 'aria-label' ) ||
2331+ ( element as HTMLElement ) . innerText ||
2332+ element . textContent ||
2333+ ''
2334+ )
2335+ . replace ( / \s + / g, ' ' )
2336+ . trim ( )
2337+ . slice ( 0 , 120 )
2338+ . replace ( / [ \uD800 - \uDBFF ] $ / , '' )
2339+ )
23412340
23422341 // Roles an app uses for something that APPEARS over the page. The first three
23432342 // were the whole list, which missed the most common hover affordance there
23442343 // is: a row's action bar (Slack's message shortcuts is role="toolbar"/"group"
23452344 // with an aria-label). A hover that mounted one produced no popup change, no
23462345 // target change, and so no observed effect at all — the agent concluded its
23472346 // hover had failed and escalated to clicking pixels.
2348- const visiblePopupLabels = allElements
2347+ const visiblePopups = allElements
23492348 . filter ( ( element ) =>
23502349 element . matches (
23512350 '[role="tooltip"], [role="menu"], [role="listbox"], [role="toolbar"], [role="menubar"], [role="group"][aria-label], [popover]'
@@ -2367,20 +2366,19 @@ export function readPageActionState(
23672366 rect . top < view . innerHeight
23682367 )
23692368 } )
2370- . slice ( 0 , 10 )
2371- . map ( ( element ) =>
2372- (
2373- element . getAttribute ( 'aria-label' ) ||
2374- ( element as HTMLElement ) . innerText ||
2375- element . textContent ||
2376- element . getAttribute ( 'role' ) ||
2377- ''
2378- )
2379- . replace ( / \s + / g, ' ' )
2380- . trim ( )
2381- . slice ( 0 , 120 )
2382- . replace ( / [ \uD800 - \uDBFF ] $ / , '' )
2369+ const visiblePopupLabels = visiblePopups . slice ( 0 , overlayLimit ) . map ( ( element ) =>
2370+ (
2371+ element . getAttribute ( 'aria-label' ) ||
2372+ ( element as HTMLElement ) . innerText ||
2373+ element . textContent ||
2374+ element . getAttribute ( 'role' ) ||
2375+ ''
23832376 )
2377+ . replace ( / \s + / g, ' ' )
2378+ . trim ( )
2379+ . slice ( 0 , 120 )
2380+ . replace ( / [ \uD800 - \uDBFF ] $ / , '' )
2381+ )
23842382
23852383 const scrolledRegions = allElements
23862384 . filter ( ( element ) => ( element as HTMLElement ) . scrollTop !== 0 )
@@ -2405,7 +2403,10 @@ export function readPageActionState(
24052403 popups : visiblePopupLabels ,
24062404 scroll : [ Math . round ( observedWindow . scrollY ) , ...scrolledRegions ] ,
24072405 ...( targetState ? { targetState } : { } ) ,
2408- observationTruncated : allElements . length >= stateNodeCap ,
2406+ observationTruncated :
2407+ allElements . length >= stateNodeCap ||
2408+ visibleDialogs . length > overlayLimit ||
2409+ visiblePopups . length > overlayLimit ,
24092410 }
24102411}
24112412
0 commit comments