Skip to content

Commit

Permalink
Merge pull request #6 from knuton/dimensionless-not-focusable
Browse files Browse the repository at this point in the history
Consider descendents of closed details unfocusable
  • Loading branch information
krksgbr authored Mar 17, 2024
2 parents 7996fb7 + 5342be1 commit f7bca50
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 5 deletions.
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
root = true

[*.{js,ts}]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[*.html]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
29 changes: 28 additions & 1 deletion cypress/e2e/spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,13 @@ describe("focus-shift spec", () => {

for (let pair of sequence) {
switch (pair.eventType) {
case "click":
cy.get(pair.selector).click()
break
case "focus":
cy.get(pair.selector).focus()
cy.get(pair.selector).then(($elem) => {
$elem[0].focus()
})
break
default:
cy.get("body")
Expand Down Expand Up @@ -192,6 +197,28 @@ describe("focus-shift spec", () => {
])
)

it(
"ignores contents of closed details element",
testFor("./cypress/fixtures/details.html", { className: "rows" }, [
{ eventType: "keydown", selector: "#button-1", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#summary-1", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#button-2", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#summary-1", options: keyevent({ key: "ArrowUp" }) },
{ eventType: "click", selector: "#summary-1" },
{ eventType: "focus", selector: "#summary-1" },
{ eventType: "keydown", selector: "#group-button-1", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#group-button-2", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#summary-2", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#button-2", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#summary-2", options: keyevent({ key: "ArrowUp" }) },
{ eventType: "click", selector: "#summary-2" },
{ eventType: "focus", selector: "#summary-2" },
{ eventType: "keydown", selector: "#subgroup-button-1", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#subgroup-button-2", options: keyevent({ key: "ArrowDown" }) },
{ eventType: "keydown", selector: "#button-2", options: keyevent({ key: "ArrowDown" }) }
])
)

it(
"allows canceling event handling",
testFor("./cypress/fixtures/events.html", { className: "rows" }, [
Expand Down
30 changes: 30 additions & 0 deletions cypress/fixtures/details.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="styles.css" />
<style>
button {
width: 100%;
}
</style>
</head>
<body>
<button id="button-1">First Button</button>

<details>
<summary id="summary-1">Toggled Group</summary>
<button id="group-button-1">Group Button 1</button>
<button id="group-button-2">Group Button 2</button>
<details>
<summary id="summary-2">Toggle in Toggle</summary>
<button id="subgroup-button-1">Subgroup Button 1</button>
<button id="subgroup-button-2">Subgroup Button 2</button>
</details>
</details>

<button id="button-2">Last Button</button>

<script src="../../index.js"></script>
</body>
</html>
7 changes: 7 additions & 0 deletions examples/everything-bagel.html
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@
<button>Normal Button 3</button>
</div>

<details>
<summary>Multiple buttons behind a toggle</summary>
<button>Normal Button 1</button>
<button>Normal Button 2</button>
<button>Normal Button 3</button>
</details>

<div class="nav-group" data-focus-group>
<em>Default group</em>
<div><button>Button 1</button></div>
Expand Down
31 changes: 27 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ function getFocusableElements(container) {
* - it has negative tabindex,
* - it has been marked with `data-focus-skip`,
* - it is a descendant of an element marked with `data-focus-skip`,
* - it is a descendant of a closed `details` element,
* - it is `disabled`,
* - it is `inert`.
*
Expand All @@ -148,20 +149,42 @@ function getFocusableElements(container) {
function isFocusable(element) {
// Has negative tabindex attribute explicitly set
if (parseInt(element.getAttribute("tabindex") || "", 10) <= -1) return false
// Is inert
if ("inert" in element && element.inert) return false
// Is disabled
if ("disabled" in element && element.disabled) return false
// Is or descends from skipped element
if (
element.hasAttribute("data-focus-skip") ||
element.closest("[data-focus-skip]") != null
)
return false
// Is inert
if ("inert" in element && element.inert) return false
// Is disabled
if ("disabled" in element && element.disabled) return false
// Descends from closed details element
if (hasClosedDetailsAncestor(element)) return false

return true
}

/**
* Tests whether the element is contained within a closed `details` element.
*
* `summary` elements are excluded (return value `false`) if they are the summary of the top-most
* closed `details` element.
*
* @param {Element} element
* @returns {boolean} - True if the element is hidden because of descending from closed `details`
*/
function hasClosedDetailsAncestor(element) {
if (element.parentElement == null) return false

const parentElement = element.parentElement
if (element.tagName === "SUMMARY") {
return hasClosedDetailsAncestor(parentElement)
} else {
return parentElement.closest("details:not([open])") != null
}
}

/**
* Get all candidates for receiving focus when moving from the active element in the given direction.
*
Expand Down

0 comments on commit f7bca50

Please sign in to comment.