import { Box, Text, UseInput } from "./Ink"; import React, { useMemo, useState } from "react"; type SelectableListProps = { height: number; width: number; items: Array; onItemSelected: (item: Item) => void; item: { key: (item: Item) => string; label: (item: Item) => string; }; selected?: Array; useInput: UseInput; }; export const SelectableList = ({ height, width, item: { key, label }, items, onItemSelected, selected = [], useInput, }: SelectableListProps) => { const scrollMargin = Math.ceil(height / 10); const [hoverIndex, setHoverIndex] = useState(0); const scrollOffset = useMemo( () => hoverIndex > items.length - height ? Math.max(items.length - height, 0) : hoverIndex > scrollMargin ? hoverIndex - scrollMargin : 0, [hoverIndex, scrollMargin, items], ); const displayedItems = items.slice(scrollOffset, scrollOffset + height); useInput((input, key) => { if (key.upArrow) { const newHoverIndex = Math.max(hoverIndex - 1, 0); setHoverIndex(newHoverIndex); } else if (key.downArrow) { const newHoverIndex = Math.min(hoverIndex + 1, items.length - 1); setHoverIndex(newHoverIndex); } else { if (input === " ") { onItemSelected(items[hoverIndex]!); } } }); return ( {displayedItems.map((item, index) => ( {selected.includes(item) ? "◉ " : "○ "} {label(item)} ))} ); };