Handle the delegatesFocus branch of get-the-focusable-area before rejecting non-focusable focus targets. This lets host.focus() move focus to the first focusable delegate in the shadow tree, or preserve an already-focused descendant. Treat delegatesFocus shadow hosts as focus delegates even when tabindex would otherwise make the host focusable. Skip inert delegate candidates, and reject inert shadow hosts before looking for a delegate. Check focus inertness through shadow-host ancestry so direct focus cannot enter inert shadow subtrees. Rebaseline the disabled delegatesFocus WPT now that this behavior passes. Cover delegated focus, hidden and inert delegate candidates, tabindex hosts, inert hosts and direct delegates inside inert hosts, and hosts without any focusable delegate.
57 lines
2.6 KiB
HTML
57 lines
2.6 KiB
HTML
<!DOCTYPE html>
|
|
<script src="../include.js"></script>
|
|
<input id="before">
|
|
<div id="host"></div>
|
|
<div id="tabindex-host" tabindex="0"></div>
|
|
<div id="inert-host" inert></div>
|
|
<div id="empty-host"></div>
|
|
<script>
|
|
test(() => {
|
|
const before = document.getElementById("before");
|
|
|
|
const host = document.getElementById("host");
|
|
const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true });
|
|
shadowRoot.innerHTML = `
|
|
<input id="hidden" style="display: none">
|
|
<input id="inert-delegate" inert>
|
|
<input id="delegate">
|
|
`;
|
|
|
|
before.focus();
|
|
host.focus();
|
|
println(`after delegatesFocus host.focus(): document=${document.activeElement.id}, shadow=${shadowRoot.activeElement.id}`);
|
|
|
|
before.focus();
|
|
shadowRoot.getElementById("delegate").focus();
|
|
host.focus();
|
|
println(`after delegatesFocus already focused host.focus(): document=${document.activeElement.id}, shadow=${shadowRoot.activeElement.id}`);
|
|
|
|
const tabindexHost = document.getElementById("tabindex-host");
|
|
const tabindexShadowRoot = tabindexHost.attachShadow({ mode: "open", delegatesFocus: true });
|
|
tabindexShadowRoot.innerHTML = `<input id="tabindex-delegate">`;
|
|
|
|
before.focus();
|
|
tabindexHost.focus();
|
|
println(`after delegatesFocus tabindex host.focus(): document=${document.activeElement.id}, shadow=${tabindexShadowRoot.activeElement.id}`);
|
|
|
|
const inertHost = document.getElementById("inert-host");
|
|
const inertShadowRoot = inertHost.attachShadow({ mode: "open", delegatesFocus: true });
|
|
inertShadowRoot.innerHTML = `<input id="inert-host-delegate">`;
|
|
|
|
before.focus();
|
|
inertHost.focus();
|
|
println(`after delegatesFocus inert host.focus(): document=${document.activeElement.id}, shadow=${inertShadowRoot.activeElement ? inertShadowRoot.activeElement.id : "null"}`);
|
|
|
|
before.focus();
|
|
inertShadowRoot.getElementById("inert-host-delegate").focus();
|
|
println(`after direct inert host delegate.focus(): document=${document.activeElement.id}, shadow=${inertShadowRoot.activeElement ? inertShadowRoot.activeElement.id : "null"}`);
|
|
|
|
const emptyHost = document.getElementById("empty-host");
|
|
const emptyShadowRoot = emptyHost.attachShadow({ mode: "open", delegatesFocus: true });
|
|
emptyShadowRoot.innerHTML = `<span>not focusable</span>`;
|
|
|
|
before.focus();
|
|
emptyHost.focus();
|
|
println(`after delegatesFocus empty host.focus(): ${document.activeElement.id}`);
|
|
});
|
|
</script>
|