import "./timeline.css"; import type * as React from "react"; import { type ReactNode } from "react"; import { useRender } from "@base-ui/react/use-render"; import { type IconName } from "./icon"; import { type StyleProps } from "./style_props"; import { type InkColor } from "./text_ink"; export interface TimelineItem { id: string; icon: IconName; /** The node's ink ROLE. The node renders a tinted disc of it; the icon takes * the full ink. */ iconColor: InkColor; isLoading?: boolean; /** * The row's identity line — CLAMPED TO TWO LINES, because it is a scan target * before it is a sentence, and the disc centres on the label's first line. * * The clamp holds while the row is COLLAPSED and lifts when it opens, so * **never repeat the label in `details`**: `details` carries what it does not. * The clamp is the contract rather than a prop. */ label: string; /** The label is a STAND-IN the surface supplied, not a value the record holds — * render it in the placeholder tone the kit uses for an unfilled field. An * automation's entry arrives with no words in it, and "nobody has written this * up" may not look like "this is what happened". */ placeholder?: boolean; /** An always-visible sub-line under the label (a note, a detail) — clamped to * two lines, same reason. When set, the row top-aligns so `right` sits next to * the label, not centred on the block. */ description?: string; error?: string; /** * Trailing content — a duration, a badge, a status. It renders BESIDE the press * target rather than inside it: nesting a control in the row's own button is * invalid HTML and hands one click to two handlers. * * **On a row that EXPANDS, prefer putting verbs in the body instead**, where * there is no press target to share with and the verbs sit next to the content * they act on. Keep `right` for a fact. */ right?: ReactNode; details?: ReactNode; /** WHERE THIS ENTRY GOES — the record behind it, opened in one press on the * label row. It is the same press target `details` uses, so an entry declaring * both keeps the disclosure: a row cannot answer one press two ways. */ onOpen?: () => void; /** The door's accessible name — name the destination ("Open ORD-1042"). * Falls back to the label, which is what the row already reads as. */ openLabel?: string; } export interface TimelineProps extends StyleProps { items: TimelineItem[]; testID?: string; ref?: React.Ref; render?: useRender.RenderProp; } /** Vertical event log — tinted icon nodes on a hairline spine, one row per * event. Rows are plain (no boxes — the spine provides the structure); * a row becomes pressable only when it carries `details`, revealing them * inline. For horizontal milestone progress use `Stepper`. */ export declare function Timeline({ items, testID, render, ref, ...props }: TimelineProps): React.ReactElement>;