Skip to content

Commit

Permalink
Merge pull request #3 from knuton/cancelable-event
Browse files Browse the repository at this point in the history
Add cancelable focus-shift:initiate event
  • Loading branch information
krksgbr authored Feb 13, 2024
2 parents 222dae5 + bcaf616 commit 090a5a0
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ focus-shift is a lightweight, zero-dependency JavaScript library designed for ke
- Declare groups with custom focus strategies
- Mark subtrees of the DOM that should trap focus
- Mark subtrees of the DOM that should be skipped
- Dispatches events which allow canceling individual focus shifts

## Usage

Expand Down Expand Up @@ -51,7 +52,6 @@ Setting `window.FOCUS_SHIFT_DEBUG = true` lets the library log processing steps
### What the library doesn't do, but might

- Dispatch cancelable events when descending into or out of groups
- Dispatch cancelable events before applying focus to an element
- Treat elements in open shadow DOM as focusable
- Allow defining custom selectors for focusables
- Use focus heuristics based on user agent's [text direction](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)
Expand Down
13 changes: 12 additions & 1 deletion cypress/e2e/spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ describe("focus-shift spec", () => {
altKey: opts.altKey || false,
getModifierState: function (name) {
return opts.modifierState === name
}
},
repeat: opts.repeat || false
}
}

Expand Down Expand Up @@ -190,4 +191,14 @@ describe("focus-shift spec", () => {
{ eventType: "keydown", selector: "#button-2", options: keyevent({ key: "ArrowDown" }) }
])
)

it(
"allows canceling event handling",
testFor("./cypress/fixtures/events.html", { className: "rows" }, [
{ eventType: "keydown", selector: "#button-1", options: keyevent({ key: "ArrowDown", repeat: false }) },
{ eventType: "keydown", selector: "#button-2", options: keyevent({ key: "ArrowDown", repeat: false }) },
{ eventType: "keydown", selector: "#button-2", options: keyevent({ key: "ArrowDown", repeat: true }) },
{ eventType: "keydown", selector: "#button-3", options: keyevent({ key: "ArrowDown", repeat: false }) }
])
)
})
20 changes: 20 additions & 0 deletions cypress/fixtures/events.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div class="nav-group" id="no-repeats">
<div><button id="button-1">First Button</button></div>
<div><button id="button-2">Second Button</button></div>
<div><button id="button-3">Third Button</button></div>
</div>
<script src="../../index.js"></script>
<script>
document.getElementById("no-repeats").addEventListener("focus-shift:initiate", (event) => {
if (event.detail.keyboardEvent.repeat) event.preventDefault()
})
</script>
</body>
</html>
19 changes: 17 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,24 @@ function handleKeyDown(event) {
) {
return
} else {
const eventTarget = document.activeElement || document.body
const shiftFocusEvent = new CustomEvent("focus-shift:initiate", {
detail: { keyboardEvent: event },
cancelable: true,
bubbles: true
})
eventTarget.dispatchEvent(shiftFocusEvent)

logging.group(`focus-shift: ${event.key}`)
event.preventDefault()
handleUserDirection(KEY_TO_DIRECTION[event.key])
if (shiftFocusEvent.defaultPrevented) {
logging.debug(
"Handling canceled via 'focus-shift:initiate' event",
shiftFocusEvent
)
} else {
event.preventDefault()
handleUserDirection(KEY_TO_DIRECTION[event.key])
}
logging.groupEnd()
}
}
Expand Down

0 comments on commit 090a5a0

Please sign in to comment.