import type { ReactNode } from "react"; import type { DigitalDisplayMode, DigitalDisplayProps, } from "./digital-display.types.js"; const DEFAULT_WIDTH_PX = 120; const DEFAULT_HEIGHT_PX = 32; const DEFAULT_SPEED = 30; const DEFAULT_WINDOW = 8; function formatNumeric( value: number, precision: number | undefined, units: string | undefined ): string { const p = precision ?? 0; const body = Number.isFinite(value) ? value.toFixed(p) : "—"; return units !== undefined && units !== "" ? `${body} ${units}` : body; } function renderBody( mode: DigitalDisplayMode, value: number, widthPx: number, heightPx: number ): ReactNode { if (mode.kind === "numeric") { return ( {formatNumeric(value, mode.precision, mode.units)} ); } if (mode.kind === "text") { return {mode.text}; } const window = mode.windowChars ?? DEFAULT_WINDOW; const speed = mode.speedPxPerSec ?? DEFAULT_SPEED; const overflowing = mode.text.length > window; if (!overflowing) { return ( {mode.text} ); } const pixelDistance = mode.text.length * (heightPx * 0.55); const durationSec = pixelDistance / speed; const animationName = "cs-display-scroll"; return ( <> {mode.text} ); } /** * Read-only 7-segment / LCD-style display. Three modes: * `numeric` (renders `value.toFixed(precision)` with optional units), * `text` (static string), `scrolling` (overflow → CSS keyframe scroll * with `prefers-reduced-motion` honoured). */ export function DigitalDisplay(props: DigitalDisplayProps): ReactNode { const { mode, value, widthPx = DEFAULT_WIDTH_PX, heightPx = DEFAULT_HEIGHT_PX, label, ariaLabel, disabled, className, } = props; const ariaContent = mode.kind === "numeric" ? formatNumeric(value, mode.precision, mode.units) : mode.text; return ( {renderBody(mode, value, widthPx, heightPx)} {ariaContent} ); }