/**
* BarChart — categories compared by length, drawn and animated on the UI thread.
*
* Composed the same way `LineChart` is: the grid, each series, the axes and the
* readout are separate children, so a chart that wants no grid simply does not
* have one.
*
* ```tsx
*
*
*
*
*
*
* ```
*
* ## What is different from a line
*
* **The baseline is zero, and not negotiable.** A line's job is to show change,
* so it may crop its axis to the range the data actually occupies. A bar's job
* is to compare *lengths*, and a bar cropped at the bottom is a length that
* lies — twice as tall no longer means twice as much. So the domain always
* reaches zero unless `yDomain` says otherwise, and saying otherwise is opting
* into a chart that misreads.
*
* **Bands, not points.** A line has a point at each x; a bar owns a slice of
* width around it. `barGap` is the fraction of that slice left empty, so bars
* stay proportional at any width instead of needing a pixel gap that is wrong
* on half of them.
*
* **Every series is one path.** A `Bar` draws all its rectangles as subpaths of
* a single animated path, split in two so the band under the finger keeps full
* ink while the rest fade. Fifty bars is two animated props a frame rather
* than fifty, and the corners are drawn as a path because a bar is rounded on
* the end it grows towards and square on the end it grows from — which `rx`
* cannot express, since it rounds all four corners or none.
*/
import { type ReactNode } from 'react';
import { type ViewProps } from 'react-native';
import { type ChartAccessibilityProps } from '../../primitives/chart-accessibility.js';
import { type SeriesColorIndex } from '../../utils/chart.js';
type Layer = 'svg' | 'overlay' | 'header';
export type BarChartStatus = 'loading' | 'ready';
export type BarChartOrientation = 'vertical' | 'horizontal';
export type BarChartDatum = Record;
/**
* The band 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 useBarChart(): {
activeIndex: number;
activePoint: BarChartDatum | null;
xDataKey: string;
};
export interface BarChartProps extends ViewProps, ChartAccessibilityProps {
className?: string;
/** The rows. Each one is a band along the category axis. */
data: BarChartDatum[];
/** Key holding the category label. Used by the axis and the readout. */
xDataKey?: string;
/**
* `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
* `BarChart.Skeleton` for something to stand in the plot meanwhile.
*/
status?: BarChartStatus;
/** 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. Note that the derived domain
* always includes zero, and a domain that does not is a bar chart whose
* lengths cannot be compared — pass this only when you mean it.
*/
yDomain?: [number, number];
/** `vertical` grows the bars upward; `horizontal` grows them rightward. */
orientation?: BarChartOrientation;
/** Stack the series on each other instead of standing them side by side. */
stacked?: boolean;
/**
* 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;
/** Points between the segments of a stack. */
stackGap?: number;
/** Corner radius on the growing end of a bar. */
cornerRadius?: number;
/**
* Smallest length a non-zero bar is drawn at, in points. A value that rounds
* to nothing still happened, and a bar of zero height says it did not.
*/
minBarLength?: number;
/** Opacity of the bars that are not under the finger. */
fadedOpacity?: number;
/**
* The band under the finger as it moves, and `-1`/`null` when it lifts.
* Fires when the index changes, not per frame.
*/
onActiveIndexChange?: (index: number, datum: BarChartDatum | null) => void;
/** Drop the axis padding, for a bar sparkline with no axis or readout. */
compact?: boolean;
children?: ReactNode;
}
/** Imperative handle: re-run the grow-in, for a "replay" control. */
export interface BarChartHandle {
replay: () => void;
}
export interface BarChartGridProps {
/** 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 BarChartGrid({ rows, color, dashArray, opacity }: BarChartGridProps): import("react").JSX.Element;
declare namespace BarChartGrid {
var displayName: string;
var layer: Layer;
}
export interface BarChartBarProps {
/** Column in the data holding this series' values. */
dataKey: string;
/** Explicit colour. Defaults to the `--color-chart-*` token for `colorIndex`. */
color?: string;
/** Which of the five chart tokens to take. */
colorIndex?: SeriesColorIndex;
/** Corner radius, overriding the chart's. */
cornerRadius?: number;
}
/**
* One series of bars.
*
* Drawn as two paths rather than one rectangle per band: the band under the
* finger, and everything else. That is the fewest animated props that can
* still dim the rest — one path could not, since a path has one opacity, and
* a view per bar would be one animated prop per bar for the same picture.
*/
declare function BarChartBar({ dataKey, color, colorIndex, cornerRadius }: BarChartBarProps): import("react").JSX.Element;
declare namespace BarChartBar {
var displayName: string;
var layer: Layer;
}
export interface BarChartSkeletonProps {
/**
* How many placeholder bars to draw. Defaults to one per row, and to seven
* 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 rows.
*/
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 on purpose. Placeholder bars of differing heights are a distribution
* the reader has no way to tell from the real one until it changes under them,
* so these say only how many bars there will be and where the baseline is.
*
* The sweep is the part that carries the meaning. Without it a chart waiting
* for data and a chart whose values are all zero draw the same picture, and
* the reader is left to guess which one they are looking at.
*/
declare function BarChartSkeleton({ bars, duration, color }: BarChartSkeletonProps): import("react").JSX.Element | null;
declare namespace BarChartSkeleton {
var displayName: string;
var layer: Layer;
}
export interface BarChartXAxisProps {
/**
* How many labels to show. Every category by default, thinned only when the
* bands get too narrow to read — pass a number to force it lower.
*/
ticks?: number;
/** Turn a row into its label. Defaults to the value at `xDataKey`. */
format?: (datum: BarChartDatum, index: number) => string;
className?: string;
}
/**
* The category labels, 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 BarChartXAxis({ ticks, format, className }: BarChartXAxisProps): import("react").JSX.Element | null;
declare namespace BarChartXAxis {
var displayName: string;
var layer: Layer;
}
export interface BarChartYAxisProps {
/** 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 BarChartYAxis({ ticks, format, className }: BarChartYAxisProps): import("react").JSX.Element;
declare namespace BarChartYAxis {
var displayName: string;
var layer: Layer;
var axis: "y";
}
export interface BarChartTooltipProps {
/** Format one series' value. Defaults to a compact number. */
formatValue?: (value: number, key: string) => string;
/** Format the readout's heading from the row. Defaults to the value at xDataKey. */
formatX?: (datum: BarChartDatum) => string;
className?: string;
}
/**
* The readout, and the gesture that drives it.
*
* There is no crosshair. A line needs one because a point on a line has no
* width of its own to point at; a bar is already the thing being pointed at,
* so highlighting it and dimming the rest says the same thing without drawing
* a line through the chart.
*
* 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 thinner the bars, the truer that
* gets.
*/
declare function BarChartTooltip({ formatValue, formatX, className }: BarChartTooltipProps): import("react").JSX.Element | null;
declare namespace BarChartTooltip {
var displayName: string;
var layer: Layer;
}
export interface BarChartLegendProps extends ViewProps {
className?: string;
/** Prettier names for the series keys. */
labels?: Record;
}
/** A swatch and a name per series, in the order the series were declared. */
declare function BarChartLegend({ className, labels, ...props }: BarChartLegendProps): import("react").JSX.Element | null;
declare namespace BarChartLegend {
var displayName: string;
var layer: Layer;
}
export interface BarChartHeaderProps extends ViewProps {
className?: string;
/** Small line above the value — what the chart 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;
/** Prettier names for the series keys, as the legend takes. */
labels?: Record;
/**
* Draw a swatch and a name per series along the trailing edge. Prefer this to
* `BarChart.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 chart is of, what it currently reads, and
* what the colours mean.
*
* It belongs to the chart rather than to the card around it because it is about
* the *plot* — the number changes as a finger moves along the bars, and the
* legend is the series list the chart itself is holding. The card's header is a
* caption on the tray the chart sits in; this is the chart introducing itself.
*
* 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 a total when nothing is pressed
* and a band's value when something is.
*/
declare function BarChartHeader({ className, title, value, caption, labels, legend, children, ...props }: BarChartHeaderProps): import("react").JSX.Element;
declare namespace BarChartHeader {
var displayName: string;
var layer: Layer;
}
export declare const BarChart: import("react").ForwardRefExoticComponent> & {
Header: typeof BarChartHeader;
Grid: typeof BarChartGrid;
Bar: typeof BarChartBar;
Skeleton: typeof BarChartSkeleton;
XAxis: typeof BarChartXAxis;
YAxis: typeof BarChartYAxis;
Tooltip: typeof BarChartTooltip;
Legend: typeof BarChartLegend;
};
export {};
//# sourceMappingURL=index.d.ts.map