/**
* HexChart — a whole broken into parts, counted out in cells.
*
* ```tsx
*
*
*
*
*
* ```
*
* ## What it is, against the pie beside it
*
* Both divide one total. The difference is what the reader has to do to read a
* share off it. A pie asks them to compare angles, which is the hardest
* quantity there is to judge by eye; this asks them to compare *counts*, and a
* count is something anyone can check by looking. A series holding a tenth of
* the cells looks like a tenth and can be confirmed as one, which is why this
* is the better shape for a split someone is going to quote.
*
* What it gives up is precision at the small end. Every cell is a whole unit,
* so a series worth half a cell either rounds up to a full one or vanishes. It
* is a chart for shares of a few percent and up, not for a long tail.
*
* ## The field
*
* The cells are pointy-top hexagons on an offset grid, so each row nests half a
* cell into the one above it. The unfilled cells are drawn too, in the muted
* token: the field is the denominator made visible, and a honeycomb floating on
* nothing gives the eye no total to read the coloured part against.
*
* `shape` decides how the filled cells are arranged. `grid` is reading order,
* which is the arrangement a reader can actually count off. `blob` grows the
* series out from the middle of the field instead — the smallest in the centre,
* each larger one wrapped around it — which counts for nothing but shows the
* shape of the split at a glance. The blob's edge is ragged by design, and
* ragged the *same way* every time: the nudge that roughens it is a hash of
* each cell's own coordinates rather than a random number, so a re-render is
* not an animation and the same data screenshots twice.
*
* Cell counts are apportioned by largest remainder, so they add up to the
* budget exactly. A honeycomb whose parts came to one less than the whole would
* have a cell in it that nothing in the data accounts for.
*
* ## Drawing and animating
*
* Two hundred cells is two hundred nodes if each one is drawn on its own, which
* is more than this needs to spend. Every cell belonging to a series is
* concatenated into a *single* path instead, so the whole chart is one node per
* series plus one for the unfilled field — six or seven, whatever the cell
* count.
*
* That is also why the reveal is a clip rather than a per-cell stagger: the
* cells are no longer separate things to stagger. An ellipse grows from the
* centre of the field, in the field's own proportions, so the honeycomb is
* uncovered in the order the blob grew in — which is the same effect a stagger
* would have given, for one animated value instead of two hundred. A `grid`
* wipes across instead, because that is the order its cells were filled in.
*
* Touch, not hover: a series is selected by pressing one of its cells, and
* pressing it again clears the selection. There is no equivalent of a pointer
* resting somewhere without committing, so a chart that only revealed its
* numbers on hover would never reveal them at all.
*
* Colours come from the `--color-chart-*` tokens, so a chart follows the active
* theme and is put on brand by overriding those five. Nothing here hardcodes a
* hex.
*/
import { type ReactNode } from 'react';
import { type ViewProps } from 'react-native';
import { type HexShape } from '../../utils/chart.js';
/** Whether the chart is showing data or waiting for it. */
export type HexChartStatus = 'loading' | 'ready';
export type { HexShape };
/** One series. Its share is worked out from the others, so there is no maximum. */
export interface HexDatum {
/** Name for the legend, the readout and the accessibility label. */
label: string;
/** How much of the whole this series is. Negatives are treated as zero. */
value: number;
/** Explicit colour, overriding the `--color-chart-*` token. */
color?: string;
}
/** The selected series and its share, for something rendered inside the chart. */
export declare function useHexChart(): {
activeIndex: number;
activeSeries: HexDatum | null;
/** Its share of the whole, 0 to 1. */
activeFraction: number;
/** How many cells it was given, which is what the reader can count. */
activeCells: number;
};
export interface HexChartProps extends ViewProps {
className?: string;
/** One entry per series. */
data: HexDatum[];
/**
* Cells across the field. The cell size follows from it and the measured
* width, so this is the one knob for how fine the honeycomb is.
*
* More cells resolve a smaller share — twenty-one across a phone is around
* two hundred and fifty in the field, so roughly a half a percent each — at
* the cost of every cell getting smaller and harder to press.
*/
columns?: number;
/** Width over height of the field. */
aspectRatio?: number;
/**
* How much of the field the series fill, 0 to 1.
*
* Only meaningful with `shape="blob"`, where the unfilled cells are the
* margin the blob is read against; a `grid` fills every cell, because a
* waffle with a ragged last row is a waffle that has stopped being countable.
*/
density?: number;
/** How the filled cells are arranged. */
shape?: HexShape;
/**
* The gap between cells, as a share of the cell radius. Given as a share so
* the field keeps its proportions at whatever size it is measured at.
*/
cellGap?: number;
/** Milliseconds for the honeycomb to fill in. */
animationDuration?: number;
/** `loading` draws the field with nothing divided up yet. */
status?: HexChartStatus;
/** Selected series. Leave unset to let the chart track it. */
activeIndex?: number;
/** Fires with the selected series, or `-1` when the selection is cleared. */
onActiveIndexChange?: (index: number) => void;
children?: ReactNode;
}
/** Imperative handle: re-run the fill, for a "replay" control. */
export interface HexChartHandle {
replay: () => void;
}
export interface HexChartCellsProps {
/** Colour of the cells no series took. Defaults to the muted token. */
emptyColor?: string;
/** Opacity of the series that are not selected, once one is. */
dimOpacity?: number;
}
/**
* The honeycomb: the unfilled field, and one path per series over it.
*
* One part rather than one per series. Every cell shares a radius, a gap and a
* grid by definition — a chart where one series' cells could be given a size of
* their own would be a chart drawing a lie, since the whole claim of the shape
* is that one cell means the same thing wherever it appears.
*
* The field is drawn outside the reveal's clip and the series inside it, so the
* total is there from the first frame and what fills in against it is the
* split. Uncovering both together would animate the denominator, which is not
* something that changed.
*/
declare function HexChartCells({ emptyColor, dimOpacity }: HexChartCellsProps): import("react").JSX.Element | null;
declare namespace HexChartCells {
var displayName: string;
var slot: "svg";
}
export interface HexChartSkeletonProps {
color?: string;
}
/**
* The loading state: the field, with nothing divided up yet.
*
* Deliberately undivided. Placeholder shares would be a made-up split, 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 HexChartSkeleton({ color }: HexChartSkeletonProps): import("react").JSX.Element | null;
declare namespace HexChartSkeleton {
var displayName: string;
var slot: "svg";
}
export interface HexChartTooltipProps {
/** Format the selected series' value. Defaults to a compact number. */
formatValue?: (value: number, series: HexDatum) => string;
/** Show the count of cells beside the share. */
showCells?: boolean;
className?: string;
}
/**
* The press target over the honeycomb, and the label that names what was
* pressed.
*
* The label hangs *above* the selected series rather than on it: it is centred
* across that series' cells and sits clear of the highest one, so the cells
* being read are never underneath the thing reading them. Two other places it
* could go are both worse — under the finger is the one part of the chart
* nobody can see, and on the middle of the series covers the mass the reader
* just asked about.
*
* A series reaching the top of the field pushes the label back inside it, which
* is the one case it does overlap. That series is the largest one, and its
* topmost cells are the part of it a reader is least likely to be counting.
*
* A press on an unfilled cell clears the selection, the same as pressing the
* selected series again. Everything outside the honeycomb is "none of them",
* and making that gesture do nothing would leave a chart you can select in but
* not out of.
*/
declare function HexChartTooltip({ formatValue, showCells, className }: HexChartTooltipProps): import("react").JSX.Element | null;
declare namespace HexChartTooltip {
var displayName: string;
var slot: "overlay";
}
export interface HexChartLegendProps extends ViewProps {
className?: string;
/** Show each series' share of the whole beside its name. */
showValue?: boolean;
}
/**
* A swatch, a name and a share per series, under the chart and across the width
* of it. Pressable in the same way the cells are — the legend is usually the
* easier target of the two, and a series worth a couple of percent is a handful
* of cells that may not be adjacent.
*
* It wraps rather than stacking, so five or six entries take two lines instead
* of six. A key is a lookup table, and a lookup table read down a column of one
* word each is a column the eye has to walk.
*/
declare function HexChartLegend({ className, showValue, ...props }: HexChartLegendProps): import("react").JSX.Element | null;
declare namespace HexChartLegend {
var displayName: string;
var slot: "footer";
}
export interface HexChartHeaderProps 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 caveat. */
caption?: string;
/** Prettier names for the series, keyed by their `label`. */
labels?: Record;
/**
* Draw a swatch and a name per series along the trailing edge.
*
* For two or three short names. Past that use `HexChart.Legend`, which runs
* under the chart across the full width: a key of five long names crammed
* into the trailing corner of a header wraps to a column and leaves the title
* beside it a few points wide.
*/
legend?: boolean;
/** Trailing slot — a control, a badge, a range picker. Wins over `legend`. */
children?: ReactNode;
}
/**
* The strip above the honeycomb: what the chart is of, what it reads, and what
* the colours mean.
*
* It belongs to the chart rather than to the card around it because it is about
* the *series* — the number changes as one is selected, and the legend is the
* 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 even though there is a total to derive it from,
* because the formatting is not the chart's to guess: a total of 6750 is a
* count, a currency or a percentage depending on what was counted, and only the
* caller knows which.
*/
declare function HexChartHeader({ className, title, value, caption, labels, legend, children, ...props }: HexChartHeaderProps): import("react").JSX.Element;
declare namespace HexChartHeader {
var displayName: string;
var slot: "header";
}
export declare const HexChart: import("react").ForwardRefExoticComponent> & {
Header: typeof HexChartHeader;
Cells: typeof HexChartCells;
Tooltip: typeof HexChartTooltip;
Legend: typeof HexChartLegend;
Skeleton: typeof HexChartSkeleton;
};
//# sourceMappingURL=index.d.ts.map