51 lines
1.4 KiB
React
51 lines
1.4 KiB
React
import React, { useState } from "react";
|
|
import { Box, Text, useInput } from "ink";
|
|
import { theme } from "./theme.jsx";
|
|
|
|
function formatCell(v, col) {
|
|
if (v == null) return "-";
|
|
if (col.formatter) return col.formatter(v);
|
|
return String(v);
|
|
}
|
|
|
|
export function DataTable({ rows = [], schema = [], selectable = false, onSelect }) {
|
|
const [selectedIdx, setSelectedIdx] = useState(0);
|
|
|
|
useInput((input, key) => {
|
|
if (!selectable || rows.length === 0) return;
|
|
if (key.upArrow) setSelectedIdx((i) => Math.max(0, i - 1));
|
|
if (key.downArrow) setSelectedIdx((i) => Math.min(rows.length - 1, i + 1));
|
|
if (key.return && onSelect) onSelect(rows[selectedIdx]);
|
|
});
|
|
|
|
if (rows.length === 0) {
|
|
return <Text dimColor>No data.</Text>;
|
|
}
|
|
|
|
return (
|
|
<Box flexDirection="column">
|
|
<Box>
|
|
{schema.map((col) => (
|
|
<Box key={col.key} width={col.width ?? 16} marginRight={1}>
|
|
<Text bold color={theme.header}>
|
|
{col.header}
|
|
</Text>
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
{rows.map((row, idx) => (
|
|
<Box
|
|
key={idx}
|
|
backgroundColor={selectable && idx === selectedIdx ? theme.selected : undefined}
|
|
>
|
|
{schema.map((col) => (
|
|
<Box key={col.key} width={col.width ?? 16} marginRight={1}>
|
|
<Text>{formatCell(row[col.key], col)}</Text>
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
);
|
|
}
|