import { type ReactNode } from "react"; import { type ColorTokens, type ViewStyle, type TextStyle, type LayoutStyle } from "../../style/index.js"; import { type StackedSegment } from "../../charts/shared/types.js"; import { type Surface } from "./stats.styles.js"; export interface StatItem { /** Small caption above the value (e.g. "Total users"). */ label: string; /** The headline figure, pre-formatted (e.g. "12,847", "$48.2k", "3.6%"). */ value: string; /** Optional change indicator (e.g. "+12.5%"). Omit to hide. */ delta?: string; /** Muted supporting line beneath a dense metric label. */ description?: string; /** Color the delta red (a decline) instead of the default green (a rise). */ down?: boolean; /** Render the delta MUTED rather than as a rise or a decline, for a line that * qualifies the value instead of reporting a change ("last 30 days", * "3 M2M / 1 user"). Green would read as good news that is not being claimed. * Takes precedence over `down`. */ steady?: boolean; /** Optional trend series; when set (and non-empty), the metric renders a * Sparkline strip below the value that plots these points. Omit for no trend. */ spark?: number[]; /** What the trend strip plots, as its accessible name. Defaults to the * metric's own label ("Revenue trend"), which is right whenever the strip is * the VALUE's history. Set it when the strip plots the supporting line * instead ("Sign-ins per hour, last 24 hours" under a live-sessions count), * so a screen reader is not told the strip is something it is not. */ sparkLabel?: string; /** Optional composition of the value, drawn in the SAME slot as `spark` as a * proportional strip over a muted rail: the metric that decomposes but has no * trend to plot (a verified share, a queue by status) still fills its card, * so a row mixing the two reads as one finished set rather than as tiles that * came out half empty. Segments summing to zero draw the bare rail, which is * the honest picture of a metric at zero. Ignored when `spark` is set. */ share?: StackedSegment[]; /** A glyph shown opposite the label, naming what the metric counts. */ icon?: ReactNode; /** A control in the metric's header, opposite the label (a period selector, a * filter). Sits beside `icon` when both are given. */ actions?: ReactNode; /** Accent for the headline value, drawn from the categorical chart ramp so a * dashboard's tiles are tellable apart at a glance. * * Mutually exclusive; first match wins in the order listed. Omit for the * default foreground, which is what every existing call site gets. The slots * are the same eight the charts use, so a metric and the series it summarises * can carry one identity. */ chart1?: boolean; chart2?: boolean; chart3?: boolean; chart4?: boolean; chart5?: boolean; chart6?: boolean; chart7?: boolean; chart8?: boolean; } export interface StatsProps { /** The metrics to render, in order. */ items: StatItem[]; /** Borderless metric stacks on a shared surface, for nesting inside a card. */ plain?: boolean; /** Dense value-first tile for a navigation rail: a 12px inset and a 20px headline. */ compact?: boolean; /** Value-first dashboard tile with a 36px headline. */ large?: boolean; /** Optional heading shown above the metrics (mainly for the plain surface). */ title?: string; /** Draw every metric's strip on a muted track, in one bounded band. * * For a ROW of metrics, where the strips are read against each other. Without * it each strip draws only its marks, so a metric with a quiet series shows a * near-empty band beside one with a full bar and the row's densities range * from blank to solid with nothing tying them together; the eye lands on the * fullest tile rather than scanning the row. The track gives every strip the * same frame whatever its data, so a flat series reads as a chart sitting at * zero and the fill is the only thing that varies. */ framed?: boolean; /** Make each metric a tappable target (drill into the underlying detail). When * set, every metric renders as a Pressable with a button role and a pressed * affordance, so a tappable stat needs no hand-rolled Pressable. */ onPressItem?: (index: number) => void; /** E2E hook forwarded to the root element. */ testID?: string; /** Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds. */ style?: LayoutStyle; } export interface StatsSkin { /** The bordered card surface each metric sits in (shape, border, padding, shadow). */ cardSurface: (tokens: ColorTokens) => ViewStyle; denseCard: (tokens: ColorTokens, large: boolean) => ViewStyle; denseValue: (tokens: ColorTokens, large: boolean) => TextStyle; denseLabel: (tokens: ColorTokens, large: boolean) => TextStyle; denseDescription: (tokens: ColorTokens) => TextStyle; /** The parent surface the plain variant nests on. */ plainContainer: (tokens: ColorTokens) => ViewStyle; /** A plain metric's own inset and rhythm, and the rule before every metric but the first. */ plainItem: (tokens: ColorTokens, first: boolean) => ViewStyle; /** Row gap by surface (cards pack tighter, plain stacks sit roomier). */ rowGap: Record; /** Title type + spacing, by surface. */ title: (tokens: ColorTokens, surface: Surface) => TextStyle; /** The small caption above the value. */ labelText: (tokens: ColorTokens) => TextStyle; /** The headline figure type. */ valueText: (tokens: ColorTokens) => TextStyle; /** The delta type base (the tone color is layered on top by the shell). */ deltaBase: TextStyle; /** The dense surfaces' delta type base (compact and large). */ denseDeltaBase: TextStyle; /** iOS/web dim on a pressed tappable item; Android uses a ripple instead (null). */ pressedOpacity: number | null; /** Android ripple over a tappable item; null on iOS/web. */ ripple: ((tokens: ColorTokens) => { color: string; borderless: boolean; }) | null; /** Whether a tappable metric under the pointer takes the secondary wash (the web only); null elsewhere. */ hoverWash: true | null; } export declare function surfaceOf(p: StatsProps): Surface; export declare function accentOf(item: StatItem): string | null; export declare function deltaOf(item: Pick): "steady" | "down" | "up"; export declare function createStats(skin: StatsSkin): (props: StatsProps) => import("react").JSX.Element; //# sourceMappingURL=stats.shared.d.ts.map