From 2d49687ae08777aff645520ad716cc60448a4de8 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Fri, 10 Jul 2026 00:56:05 -0700 Subject: [PATCH] [eric] browser: composer finder pierces shadow DOM (Reddit shreddit, Telegram, WhatsApp, Slack build their composer inside web-component shadow roots a light-DOM querySelectorAll can't see); bounded recursive walk (depth 8, 400-node cap). Live finder-probe on real DOMs: correctly picks X's contenteditable 'Post text' + excludes the search combobox; the remaining wall is that lazy/dialog/chat-gated composers aren't rendered at scan time (detection is downstream of render) --- frontend/src/shared/browserCommandHandler.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/shared/browserCommandHandler.ts b/frontend/src/shared/browserCommandHandler.ts index 694d56b2..b2a12233 100644 --- a/frontend/src/shared/browserCommandHandler.ts +++ b/frontend/src/shared/browserCommandHandler.ts @@ -356,8 +356,19 @@ async function handleFindComposer(wv: BrowserWebview, params: Record= 80 && r.height >= 16 && s.visibility !== 'hidden' && s.display !== 'none' && s.opacity !== '0'; }; - const cands = [...document.querySelectorAll( - 'textarea, [contenteditable="true"], [role="textbox"], input[type="text"]')]; + // Pierce shadow DOM: Reddit (shreddit), Telegram, WhatsApp, Slack build their composer + // inside web-component shadow roots that a light-DOM querySelectorAll can't see. + const SEL = 'textarea, [contenteditable="true"], [role="textbox"], input[type="text"]'; + const deep = (root, out, depth) => { + if (depth > 8 || out.length > 400) return out; + let kids; try { kids = root.querySelectorAll('*'); } catch (e) { return out; } + for (const el of kids) { + if (el.matches && el.matches(SEL)) out.push(el); + if (el.shadowRoot) deep(el.shadowRoot, out, depth + 1); + } + return out; + }; + const cands = deep(document, [], 0); let best = null, bestScore = 0, bestNear = false; for (const el of cands) { if (!vis(el) || el.readOnly || el.disabled) continue;