/** * LineChart — a time series, drawn and animated on the UI thread. * * The chart is composed rather than configured: the grid, each series, the * axis and the crosshair are separate children, so a chart that wants no grid * simply does not have one. A single component with twenty booleans is how * charts end up unreadable at the call site. * * ```tsx * * * * * * * * ``` * * Internally there are two layers, and the parts sort themselves into the * right one: the geometry is SVG, and anything with text or a gesture on it is * a React Native view laid over the top. That split is not a detail — SVG text * ignores the platform's text scaling and the theme's font, and a gesture * handler cannot be attached to an SVG node at all. * * Three things animate, each for a different reason: * * - **The reveal.** On mount the plot is uncovered left to right by an animated * clip rectangle. Everything inside shares that clip, so the line, its fill * and its markers arrive together rather than as three separate effects. * - **The y-domain.** When the data changes the *scale* is tweened rather than * the path swapped, so a series that grows is redrawn against a moving axis * instead of jumping to a new shape. The reveal does not replay — it happened * once, and repeating it on every refresh turns a data update into an * animation. * - **The crosshair.** A drag resolves the nearest index on the UI thread and * moves the line and the dots from there. Only the index crosses back into * JS, and only when it changes, so a drag costs a handful of re-renders * rather than one per frame. * * Colours come from the `--color-chart-*` tokens, so a chart follows the active * theme and is put on brand by overriding those five in the app's own * global.css. Nothing here hardcodes a hex. */ import { type ReactNode } from 'react'; import { type ViewProps } from 'react-native'; import { type ChartAccessibilityProps } from '../../primitives/chart-accessibility.js'; /** * Which layer a part belongs to. Read off the component itself, so composition * stays a flat list of children instead of two nested slots the caller has to * remember the order of. */ type Layer = 'svg' | 'series' | 'overlay' | 'header'; export type LineChartStatus = 'loading' | 'ready'; export type LineChartCurve = 'monotone' | 'linear'; export type LineChartDatum = Record; /** * The point under the crosshair, for something rendered *inside* the chart. * * A readout usually belongs in the card's header, which is outside this * provider — use `onActiveIndexChange` for that. A hook cannot reach up out of * the subtree it is called in, and pretending otherwise is how a component * ends up with a context that has to wrap half the screen. */ export declare function useLineChart(): { activeIndex: number; activePoint: LineChartDatum | null; xDataKey: string; }; export interface LineChartProps extends ViewProps, ChartAccessibilityProps { className?: string; /** The rows. Each one is a point along the x-axis. */ data: LineChartDatum[]; /** Key holding the x label. Used by the axis and the crosshair readout. */ xDataKey?: string; /** * `loading` draws a flat skeleton with a sweep running along it, and morphs * into the real series when it turns `ready`. One component throughout, * rather than a spinner swapped for a chart — swapping loses the transition. */ status?: LineChartStatus; /** Width ÷ height. `2` is the wide card shape; `1.6` suits a narrow column. */ aspectRatio?: number; /** Milliseconds for the reveal on mount. */ animationDuration?: number; /** Milliseconds for the y-axis to settle after the data changes. */ domainDuration?: number; /** Fix the y-axis instead of deriving it from the data. */ yDomain?: [number, number]; /** `monotone` never overshoots between points; `linear` joins them straight. */ curve?: LineChartCurve; /** * The point under the crosshair as it moves, and `-1`/`null` when the finger * lifts. This is how a readout in the card's header gets its value — that * header is outside the chart, so it cannot use `useLineChart`. * * Fires when the index changes, not per frame. */ onActiveIndexChange?: (index: number, datum: LineChartDatum | null) => void; /** * Drop the axis padding so the line reaches the edges — for a sparkline with * no grid, axis or crosshair, where the shape is the whole point. */ compact?: boolean; children?: ReactNode; } /** Imperative handle: re-run the reveal on demand, for a "replay" control. */ export interface LineChartHandle { replay: () => void; } export interface LineChartGridProps { /** Horizontal rules across the plot. */ rows?: number; color?: string; /** Dash pattern, e.g. `"4,6"`. Omit for a solid rule. */ dashArray?: string; opacity?: number; } /** Horizontal reference lines. Drawn under everything, outside the reveal clip. */ declare function LineChartGrid({ rows, color, dashArray, opacity }: LineChartGridProps): import("react").JSX.Element; declare namespace LineChartGrid { var displayName: string; var layer: Layer; } export interface LineChartLineProps { /** Key holding this series' y values. */ dataKey: string; /** * Stroke colour. Defaults to the `--color-chart-*` token at `colorIndex`, so * a series follows the theme without the call site naming a colour. */ color?: string; /** Which `--color-chart-*` token to take when `color` is not given. */ colorIndex?: 1 | 2 | 3 | 4 | 5; strokeWidth?: number; /** Dash pattern, e.g. `"6,4"` — for a projection or a secondary series. */ dashArray?: string; /** A dot at every point. Best kept for short series. */ showMarkers?: boolean; } /** One series. */ declare function LineChartLine({ dataKey, color, colorIndex, strokeWidth, dashArray, showMarkers, }: LineChartLineProps): import("react").JSX.Element; declare namespace LineChartLine { var displayName: string; var layer: Layer; } export interface LineChartAreaProps { dataKey: string; color?: string; colorIndex?: 1 | 2 | 3 | 4 | 5; /** Opacity at the line. Fades to nothing at the baseline. */ opacity?: number; } /** * The fill under a series. A separate child from the line, because a chart with * two series usually wants the fill on only one of them — two translucent * fills over each other make a third colour that means nothing. */ declare function LineChartArea({ dataKey, color, colorIndex, opacity }: LineChartAreaProps): import("react").JSX.Element; declare namespace LineChartArea { var displayName: string; var layer: Layer; } export interface LineChartSkeletonProps { /** Milliseconds for one pass of the sweep. */ duration?: number; color?: string; } /** * The loading state: a flat rule where the series will be, with a highlight * travelling along it. Drawn inside the same SVG rather than as an overlay, so * arriving data is one tree changing rather than one view replacing another — * which is what lets the flat line become the series instead of cutting to it. */ declare function LineChartSkeleton({ duration, color }: LineChartSkeletonProps): import("react").JSX.Element | null; declare namespace LineChartSkeleton { var displayName: string; var layer: Layer; } export interface LineChartXAxisProps { /** How many labels to show. The rest are dropped, evenly. */ ticks?: number; /** Turn a row into its label. Defaults to the value at `xDataKey`. */ format?: (datum: LineChartDatum, index: number) => string; className?: string; } /** * The x labels. 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 LineChartXAxis({ ticks, format, className }: LineChartXAxisProps): import("react").JSX.Element; declare namespace LineChartXAxis { var displayName: string; var layer: Layer; } export interface LineChartYAxisProps { /** How many intervals to divide the axis into. Yields `ticks + 1` labels. */ ticks?: number; /** Turn a value into its label. Defaults to a compact number. */ format?: (value: number) => string; className?: string; } /** * Value labels down the side, one per grid line. * * Give it the same `ticks` as the grid, or the numbers name lines that are not * there. Four is the default on both for that reason. * * The labels are the domain the data settles at, not the tweening one — a * number that counts up through every intermediate value while the axis * animates is noise, and the axis is the part of the chart that is supposed to * hold still enough to read. */ declare function LineChartYAxis({ ticks, format, className }: LineChartYAxisProps): import("react").JSX.Element; declare namespace LineChartYAxis { var displayName: string; var layer: Layer; var axis: "y"; } export interface LineChartTooltipProps { color?: string; /** * Float a small label at the crosshair showing the x-value and each series' * value at that point — the minimal readout a drag wants. On by default. */ showLabel?: boolean; /** Format one series' value for the label. Defaults to a compact number. */ formatValue?: (value: number, key: string) => string; /** Format the label's heading from the row. Defaults to the value at xDataKey. */ formatX?: (datum: LineChartDatum) => string; } /** * The crosshair, the gesture that drives it, and the label that rides it. * * They live in the view layer: a gesture handler cannot be attached to an SVG * node, and once the gesture is a view the crosshair may as well be one too — * a 1px view moved by `translateX` costs less than re-rendering an SVG line. * The label follows on the UI thread the same way; only its *text* crosses back * into JS, and only when the active index changes. * * The hit area is the whole plot. A crosshair you have to land on the line to * summon is a crosshair nobody finds. */ declare function LineChartTooltip({ color, showLabel, formatValue, formatX }: LineChartTooltipProps): import("react").JSX.Element | null; declare namespace LineChartTooltip { var displayName: string; var layer: Layer; } export interface LineChartLegendProps extends ViewProps { className?: string; /** Label per series key. A key with no label falls back to the key itself. */ labels?: Record; } /** * A swatch and a name per registered series. Sits in the top-left of the plot * by default — move it with `className`. */ declare function LineChartLegend({ className, labels, ...props }: LineChartLegendProps): import("react").JSX.Element | null; declare namespace LineChartLegend { var displayName: string; var layer: Layer; } export interface LineChartHeaderProps 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 * `LineChart.Legend` on a chart that has a header: the legend floats over the * plot, where it competes with the lines 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 line, 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 point's value when something is. */ declare function LineChartHeader({ className, title, value, caption, labels, legend, children, ...props }: LineChartHeaderProps): import("react").JSX.Element; declare namespace LineChartHeader { var displayName: string; var layer: Layer; } export declare const LineChart: import("react").ForwardRefExoticComponent> & { Header: typeof LineChartHeader; Grid: typeof LineChartGrid; Area: typeof LineChartArea; Line: typeof LineChartLine; Skeleton: typeof LineChartSkeleton; XAxis: typeof LineChartXAxis; YAxis: typeof LineChartYAxis; Tooltip: typeof LineChartTooltip; Legend: typeof LineChartLegend; }; export {}; //# sourceMappingURL=index.d.ts.map