106 lines
2.6 KiB
JavaScript
106 lines
2.6 KiB
JavaScript
import React, { useEffect, useCallback, useRef } from "react";
|
|
import PropTypes from "prop-types";
|
|
|
|
export const KeyboardNavigation = ({
|
|
onKeyEnter,
|
|
selectPoster,
|
|
children,
|
|
list,
|
|
selected,
|
|
}) => {
|
|
const containerRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
document.onkeypress = move;
|
|
return () => {
|
|
document.onkeypress = null;
|
|
};
|
|
}, [move, list, selected]);
|
|
|
|
const move = useCallback(
|
|
(event) => {
|
|
// Only run the function if nothing else if actively focused
|
|
if (document.activeElement.tagName.toLowerCase() !== "body") {
|
|
return;
|
|
}
|
|
|
|
// Compute the grid dimentions
|
|
if (containerRef === null) {
|
|
return;
|
|
}
|
|
const containerWidth = containerRef.current.getBoundingClientRect().width;
|
|
const posterContainer =
|
|
containerRef.current.getElementsByClassName("img-thumbnail");
|
|
|
|
let posterWidth = 0;
|
|
if (posterContainer !== null && posterContainer.item(0) !== null) {
|
|
const poster = posterContainer.item(0);
|
|
posterWidth =
|
|
poster.getBoundingClientRect().width +
|
|
poster.getBoundingClientRect().left;
|
|
}
|
|
let postersPerRow =
|
|
posterWidth >= containerWidth
|
|
? 1
|
|
: Math.floor(containerWidth / posterWidth);
|
|
|
|
let diff = 0;
|
|
switch (event.key) {
|
|
case "Enter":
|
|
onKeyEnter(selected);
|
|
return;
|
|
case "l":
|
|
diff = 1;
|
|
break;
|
|
case "h":
|
|
diff = -1;
|
|
break;
|
|
case "k":
|
|
diff = -1 * postersPerRow;
|
|
break;
|
|
case "j":
|
|
diff = postersPerRow;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// Get the index of the currently selected item
|
|
const idx = list.findIndex((e) => e.imdbId === selected);
|
|
|
|
var newIdx = idx + diff;
|
|
|
|
// Handle edge cases
|
|
if (newIdx > list.length - 1) {
|
|
newIdx = list.length - 1;
|
|
} else if (newIdx < 0) {
|
|
newIdx = 0;
|
|
}
|
|
|
|
// Get the imdbID of the newly selected item
|
|
var selectedImdb = list[newIdx].imdbId;
|
|
|
|
// Select the movie
|
|
selectPoster(selectedImdb);
|
|
containerRef.current
|
|
.getElementsByClassName("img-thumbnail")
|
|
.item(newIdx)
|
|
.scrollIntoView({
|
|
behavior: "smooth",
|
|
block: "center",
|
|
inline: "nearest",
|
|
});
|
|
},
|
|
[list, onKeyEnter, selectPoster, selected]
|
|
);
|
|
|
|
return <div ref={containerRef}>{children}</div>;
|
|
};
|
|
KeyboardNavigation.propTypes = {
|
|
list: PropTypes.array,
|
|
selected: PropTypes.string,
|
|
onKeyEnter: PropTypes.func,
|
|
selectPoster: PropTypes.func,
|
|
children: PropTypes.object,
|
|
};
|