diff --git a/README.md b/README.md index 9123f89..ff776f0 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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) diff --git a/cypress/e2e/spec.cy.ts b/cypress/e2e/spec.cy.ts index 6b45db5..e6341fd 100644 --- a/cypress/e2e/spec.cy.ts +++ b/cypress/e2e/spec.cy.ts @@ -7,7 +7,8 @@ describe("focus-shift spec", () => { altKey: opts.altKey || false, getModifierState: function (name) { return opts.modifierState === name - } + }, + repeat: opts.repeat || false } } @@ -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 }) } + ]) + ) }) diff --git a/cypress/fixtures/events.html b/cypress/fixtures/events.html new file mode 100644 index 0000000..d541416 --- /dev/null +++ b/cypress/fixtures/events.html @@ -0,0 +1,20 @@ + + +
+ + + + + + + + + diff --git a/index.js b/index.js index e849923..e827d74 100644 --- a/index.js +++ b/index.js @@ -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() } }