From 9bef0d0d7ae54c429acfe69fcab50911f8b111bc Mon Sep 17 00:00:00 2001 From: linked-danis Date: Thu, 12 Mar 2026 14:08:40 +0100 Subject: [PATCH] feat: improve scroll performance Replace full DOM scans with targeted container lookup. Changes: - Add findScrollableContainer() helper - Try common selectors first (fast path) - Fallback to viewport-centered elements - Avoids querySelectorAll('*') on large pages --- packages/page-controller/src/actions.ts | 50 ++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/page-controller/src/actions.ts b/packages/page-controller/src/actions.ts index 983192f..5d5521b 100644 --- a/packages/page-controller/src/actions.ts +++ b/packages/page-controller/src/actions.ts @@ -10,6 +10,52 @@ async function waitFor(seconds: number): Promise { await new Promise((resolve) => setTimeout(resolve, seconds * 1000)) } +/** + * Find a scrollable container without scanning the entire DOM. + * Tries common selectors first, then falls back to viewport elements. + */ +function findScrollableContainer( + canScroll: (el: HTMLElement | null) => boolean +): HTMLElement | undefined { + // Try common scrollable container selectors first (fast path) + const commonSelectors = [ + '[data-scrollable="true"]', + '.scrollable', + '.overflow-auto', + '.overflow-scroll', + '[class*="scroll"]', + 'main', + 'article', + 'section', + 'aside', + ] + + for (const selector of commonSelectors) { + const containers = document.querySelectorAll(selector) + for (const container of containers) { + if (canScroll(container)) return container + } + } + + // Fallback: check elements near viewport center (more likely to be visible) + const viewportElements = document.elementsFromPoint( + window.innerWidth / 2, + window.innerHeight / 2 + ) as HTMLElement[] + + for (const el of viewportElements) { + if (canScroll(el)) return el + // Check ancestors up to 3 levels + let parent = el.parentElement + for (let i = 0; i < 3 && parent; i++) { + if (canScroll(parent)) return parent + parent = parent.parentElement + } + } + + return undefined +} + // ======= dom utils ======= export async function movePointerToElement(element: HTMLElement) { @@ -299,7 +345,7 @@ export async function scrollVertically( el = canScroll(el) ? el - : Array.from(document.querySelectorAll('*')).find(canScroll) || + : findScrollableContainer(canScroll) || (document.scrollingElement as HTMLElement) || (document.documentElement as HTMLElement) @@ -427,7 +473,7 @@ export async function scrollHorizontally( el = canScroll(el) ? el - : Array.from(document.querySelectorAll('*')).find(canScroll) || + : findScrollableContainer(canScroll) || (document.scrollingElement as HTMLElement) || (document.documentElement as HTMLElement)