mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(chrome): focus follows the caret to the field it types into
Compose for wasm never focuses the semantics node carrying the testTag. It proxies keystrokes through a hidden 1px backing input that is a sibling of the a11y tree, so the node the runner tapped never held focus and confirmFocus refused to type into every Compose text field. Focus is re-attributed to the smallest editable whose box holds the caret's centre. Centre-point rather than full containment because the caret's height comes from the text style and the field's from its layout box, so a taller font would silently drop back to refusing.
This commit is contained in:
1 parent
176b495245
commit
5fc91fdca1
3 files changed
+173
No files matched your search
@@ -649,6 +649,36 @@ func (d *Driver) Hierarchy(ctx context.Context) (string, error) {
|
||||
while (focusedElement && focusedElement.shadowRoot && focusedElement.shadowRoot.activeElement) {
|
||||
focusedElement = focusedElement.shadowRoot.activeElement;
|
||||
}
|
||||
// Descending is still not enough on Compose for Web: it takes keystrokes on a
|
||||
// 1px transparent input pinned to the caret, and that input is a SIBLING of
|
||||
// the accessibility tree rather than a node in it. DOM focus therefore never
|
||||
// reaches the semantics element carrying the test tag, so confirmFocus in
|
||||
// internal/runner/runner.go saw an unnamed element hold focus after every
|
||||
// focus tap and refused to type. Compose declares the caret's box in these
|
||||
// custom properties, which the input inherits from the container that
|
||||
// positions it, so the field being typed into is the innermost editable box
|
||||
// that caret sits in.
|
||||
const CARET_ORIGIN_PROPERTY = '--compose-internal-web-backing-input-left';
|
||||
function fieldBehindTheCaret(caretInput) {
|
||||
if (!caretInput || caretInput.tagName !== 'INPUT') return null;
|
||||
if (!getComputedStyle(caretInput).getPropertyValue(CARET_ORIGIN_PROPERTY).trim()) return null;
|
||||
const caret = caretInput.getBoundingClientRect();
|
||||
const x = (caret.left + caret.right) / 2;
|
||||
const y = (caret.top + caret.bottom) / 2;
|
||||
let field = null;
|
||||
let fieldArea = Infinity;
|
||||
for (const candidate of editableSet) {
|
||||
if (candidate === caretInput) continue;
|
||||
const box = candidate.getBoundingClientRect();
|
||||
const area = box.width * box.height;
|
||||
if (area <= 0 || area >= fieldArea) continue;
|
||||
if (x < box.left || x > box.right || y < box.top || y > box.bottom) continue;
|
||||
field = candidate;
|
||||
fieldArea = area;
|
||||
}
|
||||
return field;
|
||||
}
|
||||
focusedElement = fieldBehindTheCaret(focusedElement) || focusedElement;
|
||||
function buildTree(el, isRoot) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
// Every attribute the markup wrote, keyed as written, which is what attrs
|
||||
|
||||
Reference in new issue
Block a user