/**
* 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