/**
* FunnelChart — how many were left at each step, and where the rest went.
*
* ```tsx
*
*
*
*
*
* ```
*
* ## What it is, against the bars next door
*
* A bar chart compares quantities that need not have anything to do with each
* other. A funnel makes a much stronger claim: every stage is a *subset of the
* one above it*, in order, and the reader is being shown where a population
* drained away. That is why the stages are not sorted, why nothing is
* normalised to a total, and why the interesting number is not any stage's
* value but the ratio between two of them.
*
* It follows that the order is the caller's and never the chart's. Stages are
* steps in a process — a signup, a checkout, a support queue — and reordering
* them by size would destroy the only thing the chart is asserting. A stage
* larger than the one above it is therefore drawn as given, wider than its
* parent, because that is a real and visible data problem and hiding it would
* be the chart lying to save face.
*
* ## Drawing
*
* One ribbon running across the card, not a stack of blocks. The stages divide
* the width between them, and each is a band symmetrical about the centre line
* — as tall as its value where it starts and as tall as the next stage's where
* it ends. The sides are curves that reach past each other, so consecutive
* bands meet flush and the whole run reads as a single narrowing channel rather
* than a row of separate shapes. The slope across a band is the drop.
*
* Each band is drawn several times over, concentrically: a wide faint ring on
* the outside through to a tight near-solid core. It is a halo, and it does two
* jobs. It gives the ribbon an edge that falls off rather than stopping dead;
* and it leaves a band of low-opacity fill above and below the core that text
* can sit on and still be read.
*
* The stages arrive one after another rather than together, each growing out of
* the centre line. A funnel is a sequence, and a sequence that assembles in its
* own order tells the reader which way to read it before they have read a word.
*
* ## Reading it
*
* The readings are laid out around the ribbon rather than crowded onto one
* line: the count above the band, the name below it, and the conversion in a
* pill in the middle of the band itself. Three readings, three places, none of
* them competing for the same space — which is what keeps a stage name whole
* under a column narrow enough to fit five of them on a phone, and what keeps
* the pill legible whatever the ribbon is doing underneath it.
*
* ## Colour
*
* One hue, fading along the run, rather than a colour per stage. A funnel's
* stages are one quantity at successive moments, not five unrelated series, and
* five hues would say they were. A stage can still be given its own `color`
* when it means something — the step where the money is taken, the one being
* discussed — and that one is drawn at full strength.
*/
import { type ReactNode } from 'react';
import { type ViewProps } from 'react-native';
/** Whether the chart is showing data or waiting for it. */
export type FunnelChartStatus = 'loading' | 'ready';
/** Whether the sides of a band are drawn as curves or as straight diagonals. */
export type FunnelEdges = 'curved' | 'straight';
/** One step of the process. */
export interface FunnelDatum {
/** Name of the step, for the label, the legend and the accessibility label. */
label: string;
/** How many were left at it. Negatives are treated as zero. */
value: number;
/** Explicit colour, drawn at full strength instead of the faded hue. */
color?: string;
}
/** The selected stage and how it converted, for something drawn inside the chart. */
export declare function useFunnelChart(): {
activeIndex: number;
activeStage: FunnelDatum | null;
/** Its share of the first stage, 0 to 1. */
activeShare: number;
/** Its share of the stage above it, 0 to 1. */
activeStep: number;
};
export interface FunnelChartProps extends ViewProps {
className?: string;
/** The steps, in the order they happen. Never reordered. */
data: FunnelDatum[];
/**
* How tall the run is drawn, in points.
*
* The run is as wide as it is given and as deep as this: the width is the
* card's, but nothing in the data says how far the ribbon should taper
* through, so it is a decision rather than a measurement.
*/
height?: number;
/**
* How wide one stage is, in points.
*
* Left unset the stages divide the width between them, which is nearly always
* what a run across a card wants. Worth setting only to make a run stop short
* of the edge.
*/
stageSize?: number;
/** Space between one stage and the next, in points. */
gap?: number;
/**
* Concentric rings drawn per stage, faint and wide on the outside through to
* a near-solid core. `1` draws the band once, flat.
*/
layers?: number;
/** Whether the sides of a band are curves or straight diagonals. */
edges?: FunnelEdges;
/**
* The shortest a non-zero stage is drawn, as a share of the tallest.
*
* A stage worth a fifth of a percent of the first is a hairline: it reads as
* missing rather than as small, and "missing" is a different claim. The floor
* is only applied to stages that have something in them — a genuine zero is
* drawn as nothing, because there it is the truth.
*/
minWidth?: number;
/** The funnel's hue. Defaults to the first chart token. */
color?: string;
/** Milliseconds for one stage to grow. */
animationDuration?: number;
/** Milliseconds between one stage starting and the next. `0` for all at once. */
staggerDelay?: number;
/** `loading` draws one plain muted ribbon until the data arrives. */
status?: FunnelChartStatus;
/** Selected stage. Leave unset to let the chart track it. */
activeIndex?: number;
/** Fires with the selected stage, or `-1` when the selection is cleared. */
onActiveIndexChange?: (index: number) => void;
children?: ReactNode;
}
/** Imperative handle: re-run the entrance, for a "replay" control. */
export interface FunnelChartHandle {
replay: () => void;
}
export interface FunnelChartStagesProps {
/** Opacity of the stages that are not selected, once one is. */
dimOpacity?: number;
}
/**
* Every stage, drawn in the order the data lists them.
*
* One part rather than one per datum. A stage's near edge is the previous
* stage's far edge, so they cannot be configured apart without the ribbon
* coming apart with them — a funnel whose third stage could be given its own
* height would be a funnel drawing a shape that is not in the data.
*/
declare function FunnelChartStages({ dimOpacity }: FunnelChartStagesProps): import("react").JSX.Element | null;
declare namespace FunnelChartStages {
var displayName: string;
var slot: "svg";
}
export interface FunnelChartSkeletonProps {
color?: string;
}
/**
* The loading state: one plain ribbon over the whole run, undivided.
*
* Deliberately undivided. Placeholder stages would be an invented drop-off, and
* a reader has no way to tell an invented one from a real one until it changes
* under them — which is worse than showing nothing, because it is showing
* something wrong.
*/
declare function FunnelChartSkeleton({ color }: FunnelChartSkeletonProps): import("react").JSX.Element | null;
declare namespace FunnelChartSkeleton {
var displayName: string;
var slot: "svg";
}
/** Which ratio a stage's pill reports. */
export type FunnelShare = 'previous' | 'top' | 'none';
export interface FunnelChartLabelsProps {
className?: string;
/** Format the count. Defaults to a compact number. */
formatValue?: (value: number, stage: FunnelDatum) => string;
/** Format the conversion in the pill. Defaults to a whole percent. */
formatShare?: (share: number, stage: FunnelDatum) => string;
/**
* Which conversion the pill reports. `top` is the share of the first stage,
* which every stage has and which reads along the run as one falling series.
* `previous` is the drop from the stage above — the step-by-step reading,
* where the first stage has nothing above it and so carries no pill.
*/
share?: FunnelShare;
/** Show the count above the ribbon. */
showValue?: boolean;
/** Show the stage's name under the ribbon. */
showLabel?: boolean;
}
/**
* The readings, arranged around the ribbon: the count above the band, the name
* under it, and the conversion in a pill on the band itself.
*
* Three places rather than one line, and that is the whole point of it. Put a
* name, a count and a percentage together on one row and the row is as wide as
* all three — so at the width a phone actually has, the name is the one that
* gives way and the reader is left with "Checkout st…" against a number. Split
* around the band, each reading has the stage's full column to itself.
*
* The pill is a filled chip rather than bare text because it is the one reading
* that sits *on* the ribbon, where the fill behind it is the same token family
* as the text would be. Punched out of its own background, it reads whatever
* the band is doing underneath.
*
* The columns are pressable rather than the shape alone: a two-percent stage is
* a sliver, and the column it lives in is a target.
*/
declare function FunnelChartLabels({ className, formatValue, formatShare, share, showValue, showLabel, }: FunnelChartLabelsProps): import("react").JSX.Element | null;
declare namespace FunnelChartLabels {
var displayName: string;
var slot: "overlay";
}
/** How the key under the run is arranged. */
export type FunnelLegendLayout = 'list' | 'inline';
export interface FunnelChartLegendProps extends ViewProps {
className?: string;
/**
* `list` gives every stage a row of its own, with the names down one column
* and the numbers down another. `inline` runs them together across the width
* and wraps, which is the denser arrangement where the names are short.
*/
layout?: FunnelLegendLayout;
/** Show each stage's reading beside its name. */
showValue?: boolean;
/** Format the value in a `list` key. Defaults to a compact number. */
formatValue?: (value: number, stage: FunnelDatum) => string;
}
/**
* A swatch, a name and a reading per stage, under the run. Pressable in the
* same way the stages are.
*
* For a funnel drawn without `Labels` — a compact one on a dashboard card,
* where the run is a shape and the reading is underneath it.
*
* A row each, by default. The stages of a funnel are a sequence, and a wrapped
* centred line loses that: the reader gets a ragged block of names in which the
* order is only implied by the order they happen to be read in, and a long
* stage name breaks it across lines that no longer line up with anything. Down
* a column the order is the order, and the numbers stack into a column of their
* own that can be compared at a glance.
*/
declare function FunnelChartLegend({ className, layout, showValue, formatValue, ...props }: FunnelChartLegendProps): import("react").JSX.Element | null;
declare namespace FunnelChartLegend {
var displayName: string;
var slot: "footer";
}
export interface FunnelChartHeaderProps extends ViewProps {
className?: string;
/** Small line above the value — what the funnel 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 caveat. */
caption?: string;
/** Trailing slot — a control, a badge, a range picker. */
children?: ReactNode;
}
/**
* The strip above the run: what the funnel is of and what it reads.
*
* It belongs to the chart rather than to the card around it because it is about
* the *stages* — the number changes as one is selected. 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 even though there is a first stage to derive it
* from, because the formatting is not the chart's to guess: 41800 is a count,
* a currency or a rate depending on what was counted.
*/
declare function FunnelChartHeader({ className, title, value, caption, children, ...props }: FunnelChartHeaderProps): import("react").JSX.Element;
declare namespace FunnelChartHeader {
var displayName: string;
var slot: "header";
}
export declare const FunnelChart: import("react").ForwardRefExoticComponent> & {
Header: typeof FunnelChartHeader;
Stages: typeof FunnelChartStages;
Labels: typeof FunnelChartLabels;
Legend: typeof FunnelChartLegend;
Skeleton: typeof FunnelChartSkeleton;
};
export {};
//# sourceMappingURL=index.d.ts.map