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
{children}
; }; KeyboardNavigation.propTypes = { list: PropTypes.array, selected: PropTypes.string, onKeyEnter: PropTypes.func, selectPoster: PropTypes.func, children: PropTypes.object, };