/** * WaterfallChart — how a run of changes carried one total to another. * * Composed the same way the other charts are: the grid, the bars, the * connectors, the axes and the readout are separate children, so a chart that * wants no grid simply does not have one. * * ```tsx * * * * * * * * ``` * * ## What the shape is asserting * * **Every bar but a total floats.** A step's bar starts where the previous one * ended and reaches as far as its own value carries it, so the gap under it is * the running total it is acting on. That floating is the entire point: a bar * chart of the same numbers would compare the changes against each other, and * this compares each of them against the balance it moved. * * **A total is anchored to zero.** It is a reading rather than a change, so it * is measured from the baseline like an ordinary bar and drawn in a neutral * colour. Marking the opening and closing steps `total` is what gives the run * two ends to be a bridge between. * * **Three colours, and no more.** Up, down, and total. A fourth would have to * mean something the reader has to be told, and the one thing this chart has * going for it is that the direction of a bar is legible before its label is. * * **The connectors are the sequence.** Without them the bars are a row of * floating rectangles at unexplained heights; the line from one bar's end to * the next bar's start is what says the second continues the first. */ import { type ReactNode } from 'react'; import { type ViewProps } from 'react-native'; import { type ChartAccessibilityProps } from '../../primitives/chart-accessibility.js'; type Layer = 'svg' | 'overlay' | 'header'; export type WaterfallChartStatus = 'loading' | 'ready'; export type WaterfallChartOrientation = 'vertical' | 'horizontal'; /** Which of the three roles a step's bar is drawn in. */ export type WaterfallKind = 'rise' | 'fall' | 'total'; export interface WaterfallDatum { /** Name of the step, as the axis and the readout show it. */ label: string; /** * The change this step makes to the running total. * * On a `total` step it is added to the running total *before* the bar is * drawn, so `0` reads the balance as it stands and a non-zero one opens the * run at a starting balance. */ value: number; /** * Draw this step as a reading rather than a change: measured from the * baseline, in the neutral colour, and counted in the legend as a total. */ total?: boolean; /** Explicit colour for this one bar, overriding the role's. */ color?: string; } /** One step, resolved against the running total it acts on. */ export interface WaterfallStep { datum: WaterfallDatum; label: string; value: number; kind: WaterfallKind; /** Value the bar is measured from — the running total before this step. */ start: number; /** Value the bar reaches — the running total after it. */ end: number; } /** * The step under the finger, for something rendered *inside* the chart. A * readout in the card's header is outside this provider — use * `onActiveIndexChange` for that. */ export declare function useWaterfallChart(): { activeIndex: number; activeStep: WaterfallStep | null; }; /** * The running totals every step sits on. * * Split out because it is the one piece of the chart that is pure arithmetic * over the data, and every part that draws anything needs the same answer — * two parts deriving it separately is two chances for the bars and the * connectors to disagree about where a step ended. */ export declare function waterfallSteps(data: WaterfallDatum[]): WaterfallStep[]; export interface WaterfallChartProps extends ViewProps, ChartAccessibilityProps { className?: string; /** The steps, in the order they happen. */ data: WaterfallDatum[]; /** * `loading` holds the bars at the baseline and grows them into the real ones * when it turns `ready`. One component throughout, rather than a spinner * swapped for a chart — swapping loses the transition. Add a * `WaterfallChart.Skeleton` for something to stand in the plot meanwhile. */ status?: WaterfallChartStatus; /** Width ÷ height. `2` is the wide card shape. */ aspectRatio?: number; /** Milliseconds for the bars to grow in on mount. */ animationDuration?: number; /** Milliseconds for the value axis to settle after the data changes. */ domainDuration?: number; /** * Fix the value axis instead of deriving it. The derived domain always * includes zero, and one that does not is a run whose bars cannot be * compared — pass this only when you mean it. */ yDomain?: [number, number]; /** `vertical` stands the bars up; `horizontal` lays the run down the side. */ orientation?: WaterfallChartOrientation; /** * Fraction of each band left empty, `0` to `1`. A fraction rather than a * pixel gap so the proportions hold at any width. */ barGap?: number; /** Fixed bar thickness in points. Derived from the band when omitted. */ barWidth?: number; /** Corner radius on the ends of a bar. */ cornerRadius?: number; /** * Smallest length a non-zero bar is drawn at, in points. A step that rounds * to nothing still happened, and a bar of zero length says it did not. */ minBarLength?: number; /** Opacity of the bars that are not under the finger. */ fadedOpacity?: number; /** Colour of a step that adds. Defaults to the success token. */ riseColor?: string; /** Colour of a step that subtracts. Defaults to the destructive token. */ fallColor?: string; /** Colour of a `total` step. Defaults to the first chart token. */ totalColor?: string; /** * The step under the finger as it moves, and `-1`/`null` when it lifts. * Fires when the index changes, not per frame. */ onActiveIndexChange?: (index: number, step: WaterfallStep | null) => void; /** Drop the axis padding, for a run with no axis or readout. */ compact?: boolean; children?: ReactNode; } /** Imperative handle: re-run the grow-in, for a "replay" control. */ export interface WaterfallChartHandle { replay: () => void; } export interface WaterfallChartGridProps { /** How many lines to draw across the value axis. */ rows?: number; color?: string; dashArray?: string; opacity?: number; } /** * Lines across the value axis, so a bar can be read against a number rather * than only against the bar beside it. */ declare function WaterfallChartGrid({ rows, color, dashArray, opacity, }: WaterfallChartGridProps): import("react").JSX.Element; declare namespace WaterfallChartGrid { var displayName: string; var layer: Layer; } export interface WaterfallChartBarsProps { /** Corner radius, overriding the chart's. */ cornerRadius?: number; } /** * The bars. * * Six animated paths a frame rather than one per step: one per role, so the * three colours can be three fills, and each of those split into the bar under * the finger and the rest, so the others can dim without every bar carrying its * own opacity. A run of forty steps costs the same as a run of four. * * Each bar grows from its own `start` towards its `end` rather than up from the * baseline. A step is a movement from one balance to another, and growing it * from zero would animate a quantity the chart is not claiming. */ declare function WaterfallChartBars({ cornerRadius }: WaterfallChartBarsProps): import("react").JSX.Element; declare namespace WaterfallChartBars { var displayName: string; var layer: Layer; } export interface WaterfallChartConnectorsProps { color?: string; dashArray?: string; strokeWidth?: number; opacity?: number; } /** * The lines from each bar's end to the next bar's start. * * Drawn under the bars, and reaching the full width of both bands rather than * only the gap between them, so the ends are hidden behind the bars they touch * and the line reads as passing behind the run instead of stopping short of it. * * They arrive with the reveal, each one held back until the bar on its left has * finished growing — a connector drawn to a bar that is not there yet points at * nothing. */ declare function WaterfallChartConnectors({ color, dashArray, strokeWidth, opacity, }: WaterfallChartConnectorsProps): import("react").JSX.Element | null; declare namespace WaterfallChartConnectors { var displayName: string; var layer: Layer; } export interface WaterfallChartSkeletonProps { /** * How many placeholder bars to draw. Defaults to one per step, and to six * when the data has not arrived — the count is the one thing a loading chart * can be honest about only if it already has the steps. */ bars?: number; /** Milliseconds for one pass of the sweep. */ duration?: number; color?: string; } /** * The loading state: a row of short, equal stubs on the baseline, with a * highlight travelling across them. * * Equal and on the baseline on purpose. Placeholder bars at differing heights * are a run the reader has no way to tell from the real one until it changes * under them, and floating them would invent a set of running totals — which is * the one thing this chart exists to report. */ declare function WaterfallChartSkeleton({ bars, duration, color, }: WaterfallChartSkeletonProps): import("react").JSX.Element | null; declare namespace WaterfallChartSkeleton { var displayName: string; var layer: Layer; } export interface WaterfallChartXAxisProps { /** * How many labels to show. Every step by default, thinned only when the bands * get too narrow to read — pass a number to force it lower. */ ticks?: number; /** Turn a step into its label. Defaults to its `label`. */ format?: (step: WaterfallStep, index: number) => string; className?: string; } /** * The step names, one under each band it has room for. Real text rather than * SVG text, so they follow the theme's font and the platform's text scaling — * SVG text does neither. */ declare function WaterfallChartXAxis({ ticks, format, className }: WaterfallChartXAxisProps): import("react").JSX.Element | null; declare namespace WaterfallChartXAxis { var displayName: string; var layer: Layer; } export interface WaterfallChartYAxisProps { /** How many labels to show along the value axis. */ ticks?: number; /** Format a value for its label. Defaults to a compact number. */ format?: (value: number) => string; className?: string; } /** Value labels down the side, aligned to the grid lines. */ declare function WaterfallChartYAxis({ ticks, format, className }: WaterfallChartYAxisProps): import("react").JSX.Element; declare namespace WaterfallChartYAxis { var displayName: string; var layer: Layer; var axis: "y"; } export interface WaterfallChartValuesProps { /** Format a step's number. Defaults to a signed compact number. */ format?: (step: WaterfallStep, index: number) => string; className?: string; } /** * The change each step made, written at the far end of its bar. * * Signed, because on this chart the sign is the reading: a bar's direction * already says which way it went, and a label that drops the sign makes the * two directions look like the same number twice. * * Only drawn upright. Sideways the bars run across a plot whose width is a * phone's, and a number at the end of one has nowhere to go that is not on top * of the bar or off the chart. */ declare function WaterfallChartValues({ format, className }: WaterfallChartValuesProps): import("react").JSX.Element | null; declare namespace WaterfallChartValues { var displayName: string; var layer: Layer; } export interface WaterfallChartTooltipProps { /** Format the step's change. Defaults to a signed compact number. */ formatValue?: (step: WaterfallStep) => string; /** Format the running total line. Return `null` to drop it. */ formatTotal?: (step: WaterfallStep) => string | null; className?: string; } /** * The readout, and the drag that drives it. * * It reports two numbers, because a step on this chart has two: what it changed * by, and what the balance stood at afterwards. The second is the one a bar's * position encodes and its length does not, so a readout that only gave the * change would leave the reader converting the height back by eye. * * The hit area is the whole plot. A readout you have to land on the bar to * summon is a readout nobody finds — and the bars here are narrower than a bar * chart's, since the gap between them is what the connectors run through. */ declare function WaterfallChartTooltip({ formatValue, formatTotal, className, }: WaterfallChartTooltipProps): import("react").JSX.Element | null; declare namespace WaterfallChartTooltip { var displayName: string; var layer: Layer; } export interface WaterfallChartLegendProps extends ViewProps { className?: string; /** Names for the three roles. */ labels?: Partial>; } /** * A swatch and a name for each role the run actually contains. * * Three entries at most, and only the ones present — a run with no totals in it * listing a "Total" colour is a key to a colour that is not on the chart. */ declare function WaterfallChartLegend({ className, labels, ...props }: WaterfallChartLegendProps): import("react").JSX.Element | null; declare namespace WaterfallChartLegend { var displayName: string; var layer: Layer; } export interface WaterfallChartHeaderProps extends ViewProps { className?: string; /** Small line above the value — what the run is of. */ title?: string; /** The readout. The largest thing on the card, and the first thing read. */ value?: string; /** One muted line under the value — a period, a comparison, a total. */ caption?: string; /** Names for the three roles, as the legend takes. */ labels?: Partial>; /** * Draw a swatch and a name per role along the trailing edge. Prefer this to * `WaterfallChart.Legend` on a chart that has a header: the legend floats * over the plot, where it competes with the bars for the same corner. */ legend?: boolean; /** Trailing slot — a control, a badge, a range picker. Wins over `legend`. */ children?: ReactNode; } /** * The strip above the plot: what the run is of, what it currently reads, and * what the colours mean. * * The value is not derived here. A readout that follows the finger belongs to * whoever owns the data — take it from `onActiveIndexChange` and pass the * formatted string down, so one header can show the closing balance when * nothing is pressed and a step's change when something is. */ declare function WaterfallChartHeader({ className, title, value, caption, labels, legend, children, ...props }: WaterfallChartHeaderProps): import("react").JSX.Element; declare namespace WaterfallChartHeader { var displayName: string; var layer: Layer; } export declare const WaterfallChart: import("react").ForwardRefExoticComponent> & { Header: typeof WaterfallChartHeader; Grid: typeof WaterfallChartGrid; Connectors: typeof WaterfallChartConnectors; Bars: typeof WaterfallChartBars; Values: typeof WaterfallChartValues; Skeleton: typeof WaterfallChartSkeleton; XAxis: typeof WaterfallChartXAxis; YAxis: typeof WaterfallChartYAxis; Tooltip: typeof WaterfallChartTooltip; Legend: typeof WaterfallChartLegend; }; export {}; //# sourceMappingURL=index.d.ts.map