A box first in every row and one over the column for the rows shown, the selected row tinted. A filter keeps what it hides selected; another list starts over; a row that left the list drops out. Watch later has none. A box no longer counts as a typing target: a click on one left the focus there and the page's keys went dead.
33 lines
1.3 KiB
TypeScript
33 lines
1.3 KiB
TypeScript
import { useRef, type ReactNode } from "react";
|
|
import { useListNav, type NavSelection } from "../../lib/listNav";
|
|
|
|
// A plain list of cards or rows the keyboard can walk — `j`/`k`, the arrows, Enter (lib/listNav) — for
|
|
// the lists that mount every item (the Plex title, season and episode grids, the download lists, a
|
|
// playlist's table body). Nothing to count: the items and the columns per row are measured when a key
|
|
// is pressed, so an auto-fill grid's columns follow its width and a column of rows is one per row.
|
|
// Each child spreads `navItemAttrs(index)` on its root; a virtualized grid is VirtualGrid's
|
|
// `keyboardNav` instead. `as="tbody"` for a table whose rows are the items.
|
|
export default function NavGrid({
|
|
as: Tag = "div",
|
|
className,
|
|
onDelete,
|
|
selection,
|
|
children,
|
|
}: {
|
|
as?: "div" | "tbody";
|
|
className?: string;
|
|
/** The Delete key takes the focused item out (lib/listNav): its index among the items. */
|
|
onDelete?: (index: number) => void;
|
|
/** `x` selects the focused item, Esc clears (lib/listNav). */
|
|
selection?: NavSelection;
|
|
children: ReactNode;
|
|
}) {
|
|
const ref = useRef<HTMLDivElement & HTMLTableSectionElement>(null);
|
|
useListNav(ref, { enabled: true, onDelete, selection });
|
|
return (
|
|
<Tag ref={ref} className={className}>
|
|
{children}
|
|
</Tag>
|
|
);
|
|
}
|