import type { HTMLAttributes, ReactNode } from "react"; import { cx } from "../../utils/cx.utils"; import { formatLogTimestamp } from "../../utils/log.utils"; import { PatternOverlay } from "../pattern-overlay/pattern-overlay.component"; import "./log.component.css"; /** Severity of a {@link Log.Item}. */ export type LogState = "info" | "warning" | "error" | "critical"; const badgeGlyph: Record = { info: "i", warning: "!", error: "x", critical: "‼", }; /** * Small marker box rendered in front of a {@link Log.Item}'s badge: no * border for `"info"`, black-filled for `"warning"`/`"error"`, and filled * with diagonal black lines for `"critical"`. */ function LogMarker({ state }: { state: LogState }) { if (state === "critical") { return ( ); } return ( ); } /** Props accepted by {@link Log}. */ export interface LogProps extends Omit, "title"> { /** Optional title rendered above the list of entries. */ title?: ReactNode; /** Whether the log is wrapped in a 2px solid border. Defaults to `true`. */ withBorder?: boolean; } /** Props accepted by {@link Log.Item}. */ export interface LogItemProps extends HTMLAttributes { /** Severity of the entry, shown as a badge on the left. */ state: LogState; /** Moment the entry occurred, rendered as `hh:mm:ss:ms`. */ timeStamp: Date; /** Optional origin of the entry, rendered next to the time. */ source?: ReactNode; /** Whether to render a small "ACK" box on the right side. */ ack?: boolean; /** Description of the entry. */ children: ReactNode; } /** * Single entry of a {@link Log}: a severity badge, a timestamp, an optional * source, a description, and an optional acknowledgement indicator. * * @example * ```tsx * * Cycle aborted * * ``` */ function LogItem({ className, state, timeStamp, source, ack, children, ...rest }: LogItemProps) { return (
{badgeGlyph[state]} {formatLogTimestamp(timeStamp)} {source != null && {source}} {children} {ack && ACK}
); } /** * Fullwidth log of {@link Log.Item}s, each showing a severity badge, a * timestamp, an optional source, a description, and an optional * acknowledgement indicator. * * @example * ```tsx * * * Safety guard opened during motion * * * Cycle aborted * * * ``` */ export function Log({ className, title, withBorder = true, children, ...rest }: LogProps) { return (
{title &&
{title}
}
{children}
); } Log.Item = LogItem;