1/** @jsxImportSource @alchemy.run/sigil */
2import type { ReactNode } from "react";
3import { Box } from "./Layout.tsx";
4import { Text } from "./Typography.tsx";
5
6export interface DescriptionItem {
7 readonly label: ReactNode;
8 readonly value: ReactNode;
9}
10
11type DescriptionListProps = {
12 readonly items: ReadonlyArray<DescriptionItem>;
13 readonly labelWidth?: number;
14 /** Put values on their own line when horizontal space must not truncate them. */
15 readonly stacked?: boolean;
16};
17
18export function DescriptionList({
19 items,
20 labelWidth = 16,
21 stacked = false,
22}: DescriptionListProps) {
23 return (
24 <Box flexDirection="column" gap={stacked ? 1 : 0}>
25 {items.map((item, index) => (
26 <Box key={index} flexDirection={stacked ? "column" : "row"}>
27 <Box width={stacked ? undefined : labelWidth} paddingRight={1}>
28 <Text tone="muted">{item.label}</Text>
29 </Box>
30 <Box paddingLeft={stacked ? 1 : 0}>
31 {/* Element values render bare: a Box (e.g. multi-line AnsiText
32 output) cannot nest inside Text. */}
33 {typeof item.value === "string" ||
34 typeof item.value === "number" ? (
35 <Text>{item.value}</Text>
36 ) : (
37 item.value
38 )}
39 </Box>
40 </Box>
41 ))}
42 </Box>
43 );
44}