2022-08-22 12:20:24 +00:00
|
|
|
"use babel";
|
|
|
|
|
|
|
|
function handleEnter({ event, currentIndex, availableElements }) {
|
|
|
|
let clickElement;
|
|
|
|
if (currentIndex === 0) {
|
|
|
|
clickElement = availableElements[currentIndex + 1];
|
|
|
|
} else {
|
|
|
|
clickElement = availableElements[currentIndex];
|
|
|
|
}
|
2022-08-23 01:49:14 +00:00
|
|
|
if (clickElement === undefined) return;
|
2022-08-22 12:20:24 +00:00
|
|
|
clickElement.click();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleArrowKey({ event, currentIndex, availableElements }) {
|
|
|
|
// If the focus isn't in the container, focus on the first thing
|
|
|
|
if (currentIndex === -1) availableElements[0].focus();
|
|
|
|
|
|
|
|
// Move the focus up or down
|
|
|
|
let nextElement;
|
|
|
|
if (event.key === "ArrowDown") {
|
|
|
|
nextElement = availableElements[currentIndex + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.key === "ArrowUp") {
|
|
|
|
nextElement = availableElements[currentIndex - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
nextElement && nextElement.focus();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implement arrow key navigation for the given parentNode
|
|
|
|
* @param {object} options
|
|
|
|
* @param {Event} options.e Keydown event
|
|
|
|
* @param {DOMNode} options.parentNode The parent node to operate on. Arrow keys won't navigate outside of this node
|
|
|
|
* @param {String} options.selectors Selectors for elements we want to be able to key through
|
|
|
|
*/
|
|
|
|
export default function handleEvents({
|
|
|
|
event,
|
|
|
|
parentNode,
|
2022-08-23 01:49:14 +00:00
|
|
|
modal,
|
2022-08-22 12:20:24 +00:00
|
|
|
selectors = "a,button,input",
|
|
|
|
}) {
|
|
|
|
if (!parentNode) return;
|
|
|
|
|
|
|
|
const key = event.key;
|
2022-08-23 01:49:14 +00:00
|
|
|
if (!["ArrowUp", "ArrowDown", "Enter", "Escape"].includes(key)) {
|
2022-08-22 12:20:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const activeElement = document.activeElement;
|
|
|
|
|
|
|
|
// If we're not inside the container, don't do anything
|
|
|
|
if (!parentNode.contains(activeElement)) return;
|
|
|
|
|
|
|
|
// Get the list of elements we're allowed to scroll through
|
|
|
|
const availableElements = parentNode.querySelectorAll(selectors);
|
|
|
|
|
|
|
|
// No elements are available to loop through.
|
|
|
|
if (!availableElements.length) return;
|
|
|
|
|
|
|
|
// Which index is currently selected
|
|
|
|
const currentIndex = Array.from(availableElements).findIndex(
|
|
|
|
(availableElement) => availableElement === activeElement
|
|
|
|
);
|
|
|
|
|
|
|
|
if (key === "Enter") {
|
|
|
|
handleEnter({ event, currentIndex, availableElements });
|
|
|
|
}
|
2022-08-23 01:49:14 +00:00
|
|
|
|
|
|
|
if (key === "Escape") {
|
|
|
|
modal();
|
|
|
|
event.preventDefault();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-22 12:20:24 +00:00
|
|
|
handleArrowKey({ event, currentIndex, availableElements });
|
|
|
|
}
|