import type { ReactNode } from "react";
import { t } from "../../i18n";
import { blendHex } from "../../theme/colors";
import { useThemeColors } from "../../theme/theme-context";
import { Box, Text, TextAttributes } from "../../ui";
import { truncateToDisplayWidth } from "../../utils/format";
import { headerCase } from "./header-case";
export { Prose } from "./prose";
export type { ProseProps } from "./prose";
export interface SectionHeadingProps {
title: string;
marginTop?: number;
width?: number;
wrap?: boolean;
}
export function SectionHeading({ title, marginTop = 0, width, wrap = false }: SectionHeadingProps) {
const colors = useThemeColors();
return (
{wrap || width === undefined ? headerCase(t(title)) : truncateToDisplayWidth(headerCase(t(title)), width)}
);
}
export interface SectionProps extends SectionHeadingProps {
children: ReactNode;
}
export function Section({ title, children, width, marginTop = 1, wrap }: SectionProps) {
return (
{children}
);
}
export interface KeyValueRowProps {
label: string;
value: string;
detail?: string;
color?: string;
width?: number;
labelWidth?: number;
emphasis?: boolean;
}
/** Aligned labels and values; a bounded row reserves room for an optional detail. */
export function KeyValueRow({ label, value, detail, color, width, labelWidth, emphasis = true }: KeyValueRowProps) {
const colors = useThemeColors();
const rowWidth = width === undefined ? undefined : Math.max(0, Math.floor(width));
const preferredLabelWidth = Math.max(0, labelWidth ?? (rowWidth === undefined ? 14 : Math.min(12, Math.max(8, Math.floor(rowWidth * 0.32)))));
const labelColumns = rowWidth === undefined ? preferredLabelWidth : Math.min(preferredLabelWidth, Math.max(0, rowWidth - 1));
const availableWidth = rowWidth === undefined ? undefined : rowWidth - labelColumns;
const valueWidth = availableWidth === undefined ? undefined : detail
? Math.min(availableWidth, Math.max(8, Math.floor(rowWidth! * 0.42)))
: availableWidth;
const detailWidth = availableWidth === undefined ? undefined : availableWidth - valueWidth!;
return (
{t(label)}
{valueWidth === undefined ? value : truncateToDisplayWidth(value, valueWidth)}
{detail && (detailWidth === undefined || detailWidth > 0) && (
{detailWidth === undefined ? ` ${detail}` : truncateToDisplayWidth(detail, detailWidth)}
)}
);
}
export interface BadgeProps {
label: string;
tone?: "neutral" | "accent" | "positive" | "negative" | "warning";
/** For a domain scale, such as a sentiment score or chart series. */
color?: string;
variant?: "subtle" | "solid";
}
export function Badge({ label, tone = "neutral", color, variant = "subtle" }: BadgeProps) {
const colors = useThemeColors();
const accent = color ?? (tone === "neutral" ? colors.textDim : tone === "accent" ? colors.borderFocused : colors[tone]);
const solid = variant === "solid";
const neutral = solid && tone === "neutral" && !color;
return (
{t(label)}
);
}
export interface DividerProps {
width?: number | `${number}%`;
height?: number | `${number}%`;
orientation?: "horizontal" | "vertical";
}
/** Host borders draw terminal rules and real CSS borders without text glyphs in the DOM. */
export function Divider({ width, height, orientation = "horizontal" }: DividerProps) {
const colors = useThemeColors();
const vertical = orientation === "vertical";
return (
);
}