jfs-components 0.0.84 → 0.0.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/lib/commonjs/components/AllocationComparisonChart/AllocationComparisonChart.js +299 -0
  3. package/lib/commonjs/components/AppBar/AppBar.js +36 -22
  4. package/lib/commonjs/components/AreaLineChart/AreaLineChart.js +866 -0
  5. package/lib/commonjs/components/AreaLineChart/chartMath.js +252 -0
  6. package/lib/commonjs/components/Attached/Attached.js +34 -4
  7. package/lib/commonjs/components/BubbleChart/BubbleChart.js +191 -0
  8. package/lib/commonjs/components/BubbleChart/bubblePacking.js +378 -0
  9. package/lib/commonjs/components/ClusterBubble/ClusterBubble.js +272 -0
  10. package/lib/commonjs/components/FullscreenModal/FullscreenModal.js +52 -89
  11. package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +7 -1
  12. package/lib/commonjs/components/index.js +34 -0
  13. package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
  14. package/lib/commonjs/icons/registry.js +1 -1
  15. package/lib/module/components/AllocationComparisonChart/AllocationComparisonChart.js +293 -0
  16. package/lib/module/components/AppBar/AppBar.js +36 -22
  17. package/lib/module/components/AreaLineChart/AreaLineChart.js +859 -0
  18. package/lib/module/components/AreaLineChart/chartMath.js +242 -0
  19. package/lib/module/components/Attached/Attached.js +34 -4
  20. package/lib/module/components/BubbleChart/BubbleChart.js +185 -0
  21. package/lib/module/components/BubbleChart/bubblePacking.js +370 -0
  22. package/lib/module/components/ClusterBubble/ClusterBubble.js +267 -0
  23. package/lib/module/components/FullscreenModal/FullscreenModal.js +53 -90
  24. package/lib/module/components/MetricLegendItem/MetricLegendItem.js +7 -1
  25. package/lib/module/components/index.js +4 -0
  26. package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
  27. package/lib/module/icons/registry.js +1 -1
  28. package/lib/typescript/src/components/AllocationComparisonChart/AllocationComparisonChart.d.ts +118 -0
  29. package/lib/typescript/src/components/AreaLineChart/AreaLineChart.d.ts +212 -0
  30. package/lib/typescript/src/components/AreaLineChart/chartMath.d.ts +90 -0
  31. package/lib/typescript/src/components/BubbleChart/BubbleChart.d.ts +81 -0
  32. package/lib/typescript/src/components/BubbleChart/bubblePacking.d.ts +83 -0
  33. package/lib/typescript/src/components/ClusterBubble/ClusterBubble.d.ts +76 -0
  34. package/lib/typescript/src/components/FullscreenModal/FullscreenModal.d.ts +21 -25
  35. package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +7 -1
  36. package/lib/typescript/src/components/index.d.ts +4 -0
  37. package/lib/typescript/src/icons/registry.d.ts +1 -1
  38. package/package.json +1 -1
  39. package/src/components/AllocationComparisonChart/AllocationComparisonChart.tsx +450 -0
  40. package/src/components/AppBar/AppBar.tsx +37 -24
  41. package/src/components/AreaLineChart/AreaLineChart.tsx +1161 -0
  42. package/src/components/AreaLineChart/chartMath.ts +265 -0
  43. package/src/components/Attached/Attached.tsx +36 -5
  44. package/src/components/BubbleChart/BubbleChart.tsx +319 -0
  45. package/src/components/BubbleChart/bubblePacking.ts +397 -0
  46. package/src/components/ClusterBubble/ClusterBubble.tsx +359 -0
  47. package/src/components/FullscreenModal/FullscreenModal.tsx +61 -119
  48. package/src/components/MetricLegendItem/MetricLegendItem.tsx +20 -6
  49. package/src/components/index.ts +4 -0
  50. package/src/design-tokens/Coin Variables-variables-full.json +1 -1
  51. package/src/icons/registry.ts +1 -1
@@ -0,0 +1,118 @@
1
+ import React from 'react';
2
+ import { type StyleProp, type ViewStyle } from 'react-native';
3
+ /**
4
+ * One vertical pill in the {@link AllocationComparisonChartProps.data} array.
5
+ *
6
+ * Each segment renders a single bar whose **height encodes `value`** (the
7
+ * "current" reading) and, when supplied, a **`baseline`** overlay drawn from
8
+ * the bottom up with a dashed marker line (the "recommended" reading). Both
9
+ * are measured against the same shared scale so bars and baselines are
10
+ * directly comparable across segments.
11
+ */
12
+ export type AllocationSegment = {
13
+ /** Stable React key (falls back to the array index). */
14
+ key?: React.Key;
15
+ /** Caption rendered under the bar — e.g. `"Small & Mid"`. */
16
+ label: React.ReactNode;
17
+ /**
18
+ * Primary value driving the bar's height (the "current" reading). Scaled
19
+ * against {@link AllocationComparisonChartProps.max}.
20
+ */
21
+ value: number;
22
+ /**
23
+ * Optional comparison value (the "recommended" reading). When provided, a
24
+ * filled overlay is drawn from the bottom of the bar up to this level.
25
+ * Omit to render a plain bar.
26
+ */
27
+ baseline?: number;
28
+ /**
29
+ * Whether to draw the dashed reference line + value label at the top of the
30
+ * `baseline` overlay. Defaults to `true` **only for the first segment that
31
+ * has a `baseline`** and `false` for the rest, so the marker stays a
32
+ * focused callout rather than repeating on every bar. Set explicitly to
33
+ * force it on/off per segment. Has no effect without a `baseline`.
34
+ */
35
+ showMarker?: boolean;
36
+ /**
37
+ * Text shown above the bar. Defaults to `formatValue(value)`. Pass `null`
38
+ * to hide it.
39
+ */
40
+ valueLabel?: React.ReactNode;
41
+ /**
42
+ * Text shown beside the dashed baseline marker. Defaults to
43
+ * `formatValue(baseline)`. Pass `null` to hide just the marker label while
44
+ * keeping the dashed line.
45
+ */
46
+ baselineLabel?: React.ReactNode;
47
+ /** Hard-override the bar (current) fill color. */
48
+ color?: string;
49
+ /** Hard-override the baseline (recommended) overlay color. */
50
+ baselineColor?: string;
51
+ /** Per-segment accessibility label. */
52
+ accessibilityLabel?: string;
53
+ };
54
+ export type AllocationComparisonChartProps = {
55
+ /**
56
+ * The segments to plot, left → right. Each carries its `value`, optional
57
+ * `baseline` and its `label`, so a bar can never drift from its caption.
58
+ */
59
+ data?: AllocationSegment[];
60
+ /**
61
+ * Maximum value used to scale every bar **and** baseline. Defaults to the
62
+ * largest `value`/`baseline` across `data`. Pass an explicit `max` (e.g.
63
+ * `100` for percentages) for a fixed scale.
64
+ */
65
+ max?: number;
66
+ /**
67
+ * Height in px of the bar area — i.e. the height of a bar whose value
68
+ * equals `max`. Excludes the value/caption label rows. Default: `154`.
69
+ */
70
+ height?: number;
71
+ /** Width of each pill bar in px. Default: the `segmentIndicator/track/width` token (`28`). */
72
+ barWidth?: number;
73
+ /** Show the legend row above the chart. Default: `true`. */
74
+ showLegend?: boolean;
75
+ /** Legend label for the bar (current) series. Default: `"Current"`. */
76
+ valueLegendLabel?: React.ReactNode;
77
+ /**
78
+ * Legend label for the baseline (recommended) series. Default:
79
+ * `"Recommended"`. The baseline legend item only appears when at least one
80
+ * segment defines a `baseline`.
81
+ */
82
+ baselineLegendLabel?: React.ReactNode;
83
+ /**
84
+ * Formats numeric `value`/`baseline` into the default labels. Default:
85
+ * `(v) => \`${v}%\``.
86
+ */
87
+ formatValue?: (value: number) => string;
88
+ /** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
89
+ modes?: Record<string, any>;
90
+ /** Container style override. */
91
+ style?: StyleProp<ViewStyle>;
92
+ /** Style applied to the bars row. */
93
+ chartStyle?: StyleProp<ViewStyle>;
94
+ /** Style applied to the legend row. */
95
+ legendStyle?: StyleProp<ViewStyle>;
96
+ /** Accessibility label for the whole chart. */
97
+ accessibilityLabel?: string;
98
+ };
99
+ /**
100
+ * `AllocationComparisonChart` plots a row of vertical pill bars that compare a
101
+ * **current** reading (each bar's height) against an optional **recommended**
102
+ * baseline (a filled overlay drawn from the bottom up, marked with a dashed
103
+ * line). Every bar and baseline shares a single scale, so heights are directly
104
+ * comparable across segments — no axes required.
105
+ *
106
+ * The chart is driven entirely by the `data` array: each entry pairs a
107
+ * `value`, an optional `baseline` and its `label`, so a bar can never drift
108
+ * out of sync with its caption or its baseline marker.
109
+ *
110
+ * Colors, fonts, spacing and the pill radius resolve from the Figma
111
+ * `segmentIndicator/*`, `metricLegendItem/*` and `allocationComparisonChart/*`
112
+ * tokens via the `modes` prop.
113
+ *
114
+ * @component
115
+ */
116
+ declare function AllocationComparisonChart({ data, max, height, barWidth, showLegend, valueLegendLabel, baselineLegendLabel, formatValue, modes: propModes, style, chartStyle, legendStyle, accessibilityLabel, }: AllocationComparisonChartProps): import("react/jsx-runtime").JSX.Element;
117
+ export default AllocationComparisonChart;
118
+ //# sourceMappingURL=AllocationComparisonChart.d.ts.map
@@ -0,0 +1,212 @@
1
+ import React from 'react';
2
+ import { type StyleProp, type ViewStyle } from 'react-native';
3
+ import { type Curve, type LinearScale, type ResolvedPoint } from './chartMath';
4
+ /** A single data point. Bare numbers are also accepted in `data`. */
5
+ export type ChartPoint = {
6
+ /** Position on the x domain. Defaults to the array index. */
7
+ x?: number | string;
8
+ /** Value on the y domain. */
9
+ y: number;
10
+ /**
11
+ * Marks this point as projected / low-confidence. The line segment
12
+ * ending at this point is rendered dashed.
13
+ */
14
+ projected?: boolean;
15
+ };
16
+ /** One line+area series. Pass one for a single chart, several to overlap. */
17
+ export type ChartSeries = {
18
+ /** Stable React key. */
19
+ key?: React.Key;
20
+ /** The data, either bare y-values or `ChartPoint`s. */
21
+ data: Array<number | ChartPoint>;
22
+ /** Legend / tooltip label. */
23
+ label?: string;
24
+ /**
25
+ * `Appearance / DataViz` mode used to resolve the series color from the
26
+ * `dataViz/bg` token (e.g. `Primary`, `Secondary`). Defaults cycle.
27
+ */
28
+ appearance?: string;
29
+ /** Hard-override the line + dot color (bypasses token resolution). */
30
+ color?: string;
31
+ /** Hard-override the area fill color (bypasses token resolution). */
32
+ areaColor?: string;
33
+ /** Whether to render the filled area. Defaults to `true`. */
34
+ showArea?: boolean;
35
+ /** Whether to render the line stroke. Defaults to `true`. */
36
+ showLine?: boolean;
37
+ };
38
+ export type ChartInset = {
39
+ top?: number;
40
+ bottom?: number;
41
+ left?: number;
42
+ right?: number;
43
+ };
44
+ export type GoalPinConfig = {
45
+ /** Pill content. */
46
+ value: React.ReactNode;
47
+ /** Data index the pin anchors to. Defaults to the last point. */
48
+ atIndex?: number;
49
+ /** Which series the pin anchors to. Defaults to `0`. */
50
+ seriesIndex?: number;
51
+ };
52
+ export type AreaLineChartProps = {
53
+ /**
54
+ * The series to plot. A single entry renders the "Area Line Chart"
55
+ * preset; multiple entries render the overlapping multi-series preset
56
+ * with an automatic legend.
57
+ */
58
+ series: ChartSeries[];
59
+ /** Labels rendered along the x axis (left-to-right). */
60
+ xLabels?: Array<string | number>;
61
+ /** Force the lower bound of the y domain. */
62
+ yMin?: number;
63
+ /** Force the upper bound of the y domain. */
64
+ yMax?: number;
65
+ /** Approximate number of y-axis ticks / grid lines. Defaults to `4`. */
66
+ numberOfTicks?: number;
67
+ /** Interpolation between points. Defaults to `linear` (straight segments). */
68
+ curve?: Curve;
69
+ /** Plot drawing height in px (excludes the x-axis row). Defaults to `218`. */
70
+ height?: number;
71
+ /** Fake margin inside the SVG so strokes/dots/pins are not clipped. */
72
+ contentInset?: ChartInset;
73
+ /** Toggle the background grid. Defaults to `true`. */
74
+ showGrid?: boolean;
75
+ /** Toggle the x-axis labels. Defaults to `true`. */
76
+ showXAxis?: boolean;
77
+ /** Toggle the y-axis labels. Defaults to `true`. */
78
+ showYAxis?: boolean;
79
+ /** Toggle the legend (multi-series only). Defaults to `true`. */
80
+ showLegend?: boolean;
81
+ /** Render a dot on every data point. Defaults to `false`. */
82
+ showDots?: boolean;
83
+ /** Format an x label. Receives the raw label and index. */
84
+ formatX?: (label: string | number, index: number) => React.ReactNode;
85
+ /** Format a y-axis tick label. */
86
+ formatY?: (value: number) => React.ReactNode;
87
+ /** Format a value shown in the tooltip. Defaults to `formatY`. */
88
+ formatValue?: (value: number, series: ChartSeries) => React.ReactNode;
89
+ /** Render a goal pin anchored to a data point. */
90
+ goalPin?: GoalPinConfig;
91
+ /** Controlled active index (the highlighted point). */
92
+ activeIndex?: number | null;
93
+ /** Initial active index for the uncontrolled case. */
94
+ defaultActiveIndex?: number | null;
95
+ /** Notified whenever the active index changes. */
96
+ onActiveIndexChange?: (index: number | null) => void;
97
+ /** Enable hover/press-drag interaction + tooltip. Defaults to `true`. */
98
+ interactive?: boolean;
99
+ /** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
100
+ modes?: Record<string, any>;
101
+ /** Container style override. */
102
+ style?: StyleProp<ViewStyle>;
103
+ /** Extra SVG-decorator children rendered on top of the default layers. */
104
+ children?: React.ReactNode;
105
+ /** Accessibility label for the whole chart. */
106
+ accessibilityLabel?: string;
107
+ };
108
+ type ResolvedSeries = {
109
+ key: React.Key;
110
+ label?: string;
111
+ appearance: string;
112
+ lineColor: string;
113
+ areaColor: string;
114
+ showArea: boolean;
115
+ showLine: boolean;
116
+ points: ResolvedPoint[];
117
+ };
118
+ type ChartContextValue = {
119
+ width: number;
120
+ height: number;
121
+ inset: Required<ChartInset>;
122
+ xScale: LinearScale;
123
+ yScale: LinearScale;
124
+ yTicks: number[];
125
+ /** Pixel x position for each canonical data index. */
126
+ indexXs: number[];
127
+ /** Number of canonical data points. */
128
+ count: number;
129
+ series: ResolvedSeries[];
130
+ curve: Curve;
131
+ activeIndex: number | null;
132
+ setActiveIndex: (index: number | null) => void;
133
+ xLabels?: Array<string | number>;
134
+ formatX: (label: string | number, index: number) => React.ReactNode;
135
+ formatY: (value: number) => React.ReactNode;
136
+ showDots: boolean;
137
+ modes: Record<string, any>;
138
+ };
139
+ /** Access the surrounding chart geometry from a decorator/sub-component. */
140
+ export declare function useChart(): ChartContextValue;
141
+ /**
142
+ * `AreaLineChart` is a lightweight, token-driven area/line chart built
143
+ * entirely on `react-native-svg`. A single `series` renders one filled
144
+ * area with a line on top (plus an optional goal pin); multiple `series`
145
+ * overlap with an automatic legend. It supports smooth/linear curves,
146
+ * dashed "projected" segments, a configurable grid and axes, and a
147
+ * cross-platform crosshair tooltip (hover on web, press-drag on native).
148
+ *
149
+ * The reusable building blocks (`AreaLineChart.Grid`, `.XAxis`, `.YAxis`,
150
+ * `.GoalPin`) read the shared chart geometry through `useChart()`, so you
151
+ * can also compose them manually or add your own SVG decorators as
152
+ * children.
153
+ *
154
+ * @component
155
+ */
156
+ declare function AreaLineChart({ series, xLabels, yMin, yMax, numberOfTicks, curve, height, contentInset, showGrid, showXAxis, showYAxis, showLegend, showDots, formatX, formatY, formatValue, goalPin, activeIndex: activeIndexProp, defaultActiveIndex, onActiveIndexChange, interactive, modes: propModes, style, children, accessibilityLabel, }: AreaLineChartProps): import("react/jsx-runtime").JSX.Element;
157
+ declare namespace AreaLineChart {
158
+ var Grid: typeof ChartGrid;
159
+ var XAxis: typeof ChartXAxis;
160
+ var YAxis: typeof ChartYAxis;
161
+ var GoalPin: typeof ChartGoalPin;
162
+ }
163
+ export type ChartGridProps = {
164
+ /** Which grid lines to draw. Defaults to `horizontal`. */
165
+ direction?: 'horizontal' | 'vertical' | 'both';
166
+ /** Stroke color. Defaults to a subtle grey. */
167
+ stroke?: string;
168
+ /** Stroke width. Defaults to `1`. */
169
+ strokeWidth?: number;
170
+ /** Dash pattern, e.g. `'4,4'`. Solid by default. */
171
+ strokeDasharray?: string;
172
+ };
173
+ /** Background grid lines aligned to the y-ticks (horizontal) and x data points (vertical). */
174
+ declare function ChartGrid({ direction, stroke, strokeWidth, strokeDasharray, }: ChartGridProps): import("react/jsx-runtime").JSX.Element;
175
+ export type ChartYAxisProps = {
176
+ /** Show the tick text labels. Defaults to `true`. */
177
+ showLabels?: boolean;
178
+ /** Show short tick marks next to the labels. Defaults to `false`. */
179
+ showTicks?: boolean;
180
+ /** Length of a tick mark in px. Defaults to `4`. */
181
+ tickLength?: number;
182
+ /** Show a vertical axis line. Defaults to `false`. */
183
+ showAxisLine?: boolean;
184
+ /** Override the tick label formatter. */
185
+ formatLabel?: (value: number) => React.ReactNode;
186
+ };
187
+ /** Y-axis tick labels, vertically positioned to align with the grid. */
188
+ declare function ChartYAxis({ showLabels, showTicks, tickLength, showAxisLine, formatLabel, }: ChartYAxisProps): import("react/jsx-runtime").JSX.Element;
189
+ export type ChartXAxisProps = {
190
+ /** Show the tick text labels. Defaults to `true`. */
191
+ showLabels?: boolean;
192
+ /** Show short tick marks above the labels. Defaults to `false`. */
193
+ showTicks?: boolean;
194
+ /** Length of a tick mark in px. Defaults to `4`. */
195
+ tickLength?: number;
196
+ /** Make labels tap-to-select the nearest data point. Defaults to `true`. */
197
+ selectable?: boolean;
198
+ /** Override the label formatter. */
199
+ formatLabel?: (label: string | number, index: number) => React.ReactNode;
200
+ };
201
+ /** X-axis labels, horizontally positioned to align with the data points. */
202
+ declare function ChartXAxis({ showLabels, showTicks, tickLength, selectable, formatLabel, }: ChartXAxisProps): import("react/jsx-runtime").JSX.Element;
203
+ export type ChartGoalPinProps = GoalPinConfig & {
204
+ /** Pill background. Defaults to the series color. */
205
+ color?: string;
206
+ /** Pill text color. Defaults to the `mode/Grey/2500` token (white). */
207
+ textColor?: string;
208
+ };
209
+ /** A pill marker anchored to a data point, with a dashed connector to the baseline. */
210
+ declare function ChartGoalPin({ value, atIndex, seriesIndex, color, textColor }: ChartGoalPinProps): import("react/jsx-runtime").JSX.Element;
211
+ export default AreaLineChart;
212
+ //# sourceMappingURL=AreaLineChart.d.ts.map
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Pure, framework-agnostic math helpers for `AreaLineChart`.
3
+ *
4
+ * Everything here is intentionally dependency-free (no d3, no react-native)
5
+ * so the chart can stay lightweight and be unit-reasoned in isolation. The
6
+ * functions cover the four primitives a line/area chart needs:
7
+ * 1. linear scales (data domain -> pixel range)
8
+ * 2. "nice" tick generation for the value axis
9
+ * 3. SVG path generation for lines and filled areas (straight + smooth)
10
+ * 4. interaction lookup (which data index is nearest a touch x)
11
+ */
12
+ /** A resolved point in data space. `x` is the categorical/linear index. */
13
+ export type ResolvedPoint = {
14
+ /** Position along the x domain (defaults to the array index). */
15
+ x: number;
16
+ /** Value along the y domain. */
17
+ y: number;
18
+ /**
19
+ * When true, the line segment that *ends* at this point is rendered
20
+ * dashed (used for projected / low-confidence data).
21
+ */
22
+ projected: boolean;
23
+ };
24
+ /** A point already projected into pixel space. */
25
+ export type PixelPoint = {
26
+ x: number;
27
+ y: number;
28
+ projected: boolean;
29
+ };
30
+ /** Linear interpolation scale: maps a value from `domain` into `range`. */
31
+ export type LinearScale = {
32
+ (value: number): number;
33
+ domain: readonly [number, number];
34
+ range: readonly [number, number];
35
+ };
36
+ /**
37
+ * Create a linear scale mapping `domain` -> `range`. Mirrors the subset of
38
+ * `d3-scale.scaleLinear` we rely on, without the dependency. A zero-width
39
+ * domain collapses to the midpoint of the range so we never divide by zero.
40
+ */
41
+ export declare function createLinearScale(domain: readonly [number, number], range: readonly [number, number]): LinearScale;
42
+ /**
43
+ * Generate up to ~`count` "nice" evenly-spaced tick values spanning
44
+ * `[min, max]`, snapping the step to a 1/2/5 * 10^n progression so labels
45
+ * read cleanly (e.g. 0, 30K, 60K, 90K). Returns ascending values that
46
+ * always include the rounded-down min and rounded-up max bounds.
47
+ */
48
+ export declare function niceTicks(min: number, max: number, count?: number): number[];
49
+ /**
50
+ * Compute the [min, max] extent of an array of resolved points along the
51
+ * requested axis. Returns `[0, 0]` for an empty list.
52
+ */
53
+ export declare function extent(points: ResolvedPoint[], axis: 'x' | 'y'): [number, number];
54
+ /**
55
+ * Normalize the loose `number[] | ChartPoint[]` series data into a uniform
56
+ * `ResolvedPoint[]`. Bare numbers use their array index as the x value.
57
+ */
58
+ export declare function resolvePoints(data: ReadonlyArray<number | {
59
+ x?: number | string;
60
+ y: number;
61
+ projected?: boolean;
62
+ }>): ResolvedPoint[];
63
+ export type Curve = 'linear' | 'monotone';
64
+ /**
65
+ * One drawable line segment. `dashed` mirrors the `projected` flag of the
66
+ * point the segment ends at, letting the renderer split the polyline into
67
+ * solid and dashed `Path`s.
68
+ */
69
+ export type LineSegment = {
70
+ d: string;
71
+ dashed: boolean;
72
+ };
73
+ /**
74
+ * Build the SVG path(s) for a polyline through `points`, split into runs of
75
+ * solid vs dashed segments. Each individual segment ("move to A, line/curve
76
+ * to B") is emitted as its own sub-path so that a single projected point can
77
+ * dash exactly one segment while leaving its neighbours solid.
78
+ */
79
+ export declare function buildLineSegments(points: PixelPoint[], curve: Curve): LineSegment[];
80
+ /**
81
+ * Build a single closed area path (the line, then down to `baselineY` and
82
+ * back) for a filled area fill. Curve smoothing matches `buildLineSegments`.
83
+ */
84
+ export declare function buildAreaPath(points: PixelPoint[], baselineY: number, curve: Curve): string;
85
+ /**
86
+ * Find the index of the point whose pixel-x is nearest to `targetX`. Used to
87
+ * snap the crosshair / tooltip to the closest data point during hover/drag.
88
+ */
89
+ export declare function nearestIndex(pixelXs: number[], targetX: number): number;
90
+ //# sourceMappingURL=chartMath.d.ts.map
@@ -0,0 +1,81 @@
1
+ import React from 'react';
2
+ import { type StyleProp, type ViewStyle } from 'react-native';
3
+ import { type ClusterBubbleLabelPlacement } from '../ClusterBubble/ClusterBubble';
4
+ /** One bubble in the chart. */
5
+ export type BubbleDatum = {
6
+ /** Stable React key (falls back to the array index). */
7
+ id?: React.Key;
8
+ /**
9
+ * Numeric magnitude controlling the bubble's *area*. Larger values produce
10
+ * larger circles (`sqrt`-scaled between `minBubbleSize` and `maxBubbleSize`).
11
+ */
12
+ value: number;
13
+ /**
14
+ * Bold primary text shown in/under the bubble — e.g. `"40%"`, `"₹270K"`.
15
+ * Defaults to the stringified `value`.
16
+ */
17
+ display?: React.ReactNode;
18
+ /** Secondary caption beside the primary text — e.g. `"Recommended"`. */
19
+ label?: React.ReactNode;
20
+ /** `Appearance / DataViz` mode for the fill. Cycles automatically if omitted. */
21
+ appearance?: string;
22
+ /** Hard color override (bypasses token resolution). */
23
+ color?: string;
24
+ /** Force this bubble's label placement, overriding the chart-level default. */
25
+ labelPlacement?: ClusterBubbleLabelPlacement;
26
+ /** Per-bubble accessibility label. */
27
+ accessibilityLabel?: string;
28
+ };
29
+ export type BubbleChartProps = {
30
+ /** The bubbles to lay out and render. */
31
+ data: BubbleDatum[];
32
+ /** Smallest bubble diameter in px. Defaults to `48`. */
33
+ minBubbleSize?: number;
34
+ /** Largest bubble diameter in px. Defaults to `170`. */
35
+ maxBubbleSize?: number;
36
+ /** Minimum spacing between packed bubbles in px. Defaults to `8`. */
37
+ gap?: number;
38
+ /** Gap in px between a circle's edge and its outside label. Defaults to `gap`. */
39
+ labelGap?: number;
40
+ /**
41
+ * Fixed pool height in px. When omitted, the height is derived from the
42
+ * measured width and the total bubble area so the cluster fits comfortably.
43
+ * The cluster is always confined to the `width × height` box and never
44
+ * overflows.
45
+ */
46
+ height?: number;
47
+ /** Default label placement for every bubble. Defaults to `auto`. */
48
+ labelPlacement?: ClusterBubbleLabelPlacement;
49
+ /** Diameter (px) at/above which `auto` placement renders the label inside. Defaults to `88`. */
50
+ autoInsideMinSize?: number;
51
+ /**
52
+ * Ordering of `appearance` colors assigned to bubbles that don't specify
53
+ * one. Cycles through this list in input order.
54
+ */
55
+ appearanceCycle?: string[];
56
+ /** Number of force-simulation iterations. Higher = more settled. Defaults to `500`. */
57
+ iterations?: number;
58
+ /** Notified when a bubble is pressed. Makes every bubble pressable. */
59
+ onBubblePress?: (datum: BubbleDatum, index: number) => void;
60
+ /** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
61
+ modes?: Record<string, any>;
62
+ /** Container style override. */
63
+ style?: StyleProp<ViewStyle>;
64
+ /** Accessibility label for the whole chart. */
65
+ accessibilityLabel?: string;
66
+ };
67
+ /**
68
+ * `BubbleChart` arranges a set of `ClusterBubble`s with a lightweight **force
69
+ * simulation** — bubbles repel one another (collision), a gentle gravity keeps
70
+ * the cluster balanced, and the container box acts as the walls of a pool, so
71
+ * nothing ever overflows. Each datum's `value` drives its area (`sqrt`-scaled),
72
+ * colors resolve from the `dataViz/bg` token via a cycling `appearance`, and the
73
+ * emphasis comes from the `Emphasis / DataViz` mode. When a bubble is too small
74
+ * to hold its text, the label is anchored just outside the circle on whichever
75
+ * side has the most free space.
76
+ *
77
+ * @component
78
+ */
79
+ declare function BubbleChart({ data, minBubbleSize, maxBubbleSize, gap, labelGap, height, labelPlacement, autoInsideMinSize, appearanceCycle, iterations, onBubblePress, modes: propModes, style, accessibilityLabel, }: BubbleChartProps): import("react/jsx-runtime").JSX.Element;
80
+ export default BubbleChart;
81
+ //# sourceMappingURL=BubbleChart.d.ts.map
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Dependency-free layout math for `BubbleChart`.
3
+ *
4
+ * Instead of a rigid ring, bubbles are arranged with a small **force
5
+ * simulation** — think of bubbles floating in a rectangular pool: each one
6
+ * repels the others (collision), a gentle pull keeps the cluster balanced
7
+ * (gravity), and the pool walls confine everything inside the container box so
8
+ * nothing overflows. Radii are first `sqrt`-scaled from the data magnitudes and
9
+ * down-scaled to fit the available area. Finally, for bubbles whose text must
10
+ * sit *outside* the circle, a direction chooser picks the side (top / bottom /
11
+ * left / right) with the most free space so labels avoid further collisions.
12
+ */
13
+ export type LabelDirection = 'top' | 'bottom' | 'left' | 'right';
14
+ export type PositionedNode = {
15
+ x: number;
16
+ y: number;
17
+ r: number;
18
+ };
19
+ export type LabelBox = {
20
+ /** Estimated rendered width of the outside label, in px. */
21
+ w: number;
22
+ /** Estimated rendered height of the outside label, in px. */
23
+ h: number;
24
+ };
25
+ /**
26
+ * Map magnitudes to radii so a bubble's *area* scales with its value
27
+ * (`sqrt`-encoding), clamped into `[minRadius, maxRadius]`.
28
+ */
29
+ export declare function scaleRadii(magnitudes: number[], minRadius: number, maxRadius: number): number[];
30
+ /**
31
+ * Uniformly shrink radii (preserving relative proportions) so the bubbles plus
32
+ * some breathing room and label allowance fit inside the `width × height` box.
33
+ * Returns the radii unchanged when they already fit.
34
+ */
35
+ export declare function fitRadiiToBox(radii: number[], width: number, height: number, options?: {
36
+ density?: number;
37
+ labelArea?: number;
38
+ minRadius?: number;
39
+ }): number[];
40
+ /**
41
+ * Arrange circles inside a `width × height` box with a collision + gravity
42
+ * relaxation. Bubbles never overlap (separated by at least `gap`) and are hard-
43
+ * clamped within the walls so the cluster stays inside the container.
44
+ */
45
+ export declare function simulateCluster(radii: number[], options: {
46
+ width: number;
47
+ height: number;
48
+ gap?: number;
49
+ iterations?: number;
50
+ gravity?: number;
51
+ /** Horizontal wall inset reserved for outside labels. */
52
+ insetX?: number;
53
+ /** Vertical wall inset reserved for outside labels. */
54
+ insetY?: number;
55
+ /**
56
+ * Per-node flag: `true` nodes are pulled toward the perimeter ring
57
+ * (instead of the center) so their outside labels reach the open band
58
+ * along the walls. Typically the small / outside-labelled bubbles.
59
+ */
60
+ perimeter?: boolean[];
61
+ }): PositionedNode[];
62
+ /**
63
+ * Roughly estimate the rendered size of an outside label block (a bold value
64
+ * line stacked over a lighter caption line), used purely for layout scoring.
65
+ */
66
+ export declare function estimateLabelBox(value: string, label: string, options?: {
67
+ valueFontSize?: number;
68
+ labelFontSize?: number;
69
+ }): LabelBox;
70
+ /**
71
+ * For each node that has an outside label (`labels[i]` non-null), pick the
72
+ * direction whose label rect best avoids the other circles, already-placed
73
+ * labels, and the container walls — biased to point *outward* (away from the
74
+ * cluster centroid, toward free space).
75
+ *
76
+ * Returns a direction per node, or `null` for nodes without an outside label.
77
+ */
78
+ export declare function chooseLabelDirections(nodes: PositionedNode[], labels: Array<LabelBox | null>, options: {
79
+ width: number;
80
+ height: number;
81
+ gap?: number;
82
+ }): Array<LabelDirection | null>;
83
+ //# sourceMappingURL=bubblePacking.d.ts.map
@@ -0,0 +1,76 @@
1
+ import React from 'react';
2
+ import { type StyleProp, type TextStyle, type ViewStyle } from 'react-native';
3
+ /** Where the value/label text sits relative to the circle. */
4
+ export type ClusterBubbleLabelPlacement = 'inside' | 'outside' | 'auto';
5
+ /** Which side of the circle an *outside* label is anchored to. */
6
+ export type ClusterBubbleLabelDirection = 'top' | 'bottom' | 'left' | 'right';
7
+ export type ClusterBubbleProps = {
8
+ /**
9
+ * The bold, primary content rendered in/under the bubble — e.g. `"40%"`,
10
+ * `"₹270K"`. Strings are auto-wrapped in a `<Text>`; pass a node for full
11
+ * control (e.g. a `MoneyValue`).
12
+ */
13
+ value?: React.ReactNode;
14
+ /** The secondary caption shown beside the value — e.g. `"Recommended"`. */
15
+ label?: React.ReactNode;
16
+ /** Diameter of the circle in px. Defaults to `120`. */
17
+ size?: number;
18
+ /**
19
+ * `Appearance / DataViz` mode used to resolve the fill from the
20
+ * `dataViz/bg` token (e.g. `Primary`, `Secondary`, `Tertiary`).
21
+ * Defaults to `Primary`. The *emphasis* of the fill is taken from the
22
+ * `Emphasis / DataViz` mode in `modes`.
23
+ */
24
+ appearance?: string;
25
+ /** Hard-override the circle fill color (bypasses token resolution). */
26
+ color?: string;
27
+ /**
28
+ * Where the text sits. `inside` centers it within the circle, `outside`
29
+ * anchors it just beyond the circle's edge, and `auto` (default) picks
30
+ * `inside` when the bubble is at least `autoInsideMinSize` px, otherwise
31
+ * `outside`.
32
+ */
33
+ labelPlacement?: ClusterBubbleLabelPlacement;
34
+ /**
35
+ * Which side an *outside* label is placed on. The label is positioned
36
+ * exactly `labelGap` px beyond the circle's radius in this direction.
37
+ * Defaults to `bottom`.
38
+ */
39
+ labelDirection?: ClusterBubbleLabelDirection;
40
+ /** Gap in px between the circle's edge and an outside label. Defaults to `8`. */
41
+ labelGap?: number;
42
+ /** Diameter (px) at/above which `auto` places the text inside. Defaults to `88`. */
43
+ autoInsideMinSize?: number;
44
+ /**
45
+ * Text color when the label sits *inside*. Defaults to an automatic
46
+ * black/white choice based on the fill's luminance for legibility.
47
+ */
48
+ insideTextColor?: string;
49
+ /** Press handler — wraps the bubble in a `Pressable` when provided. */
50
+ onPress?: () => void;
51
+ /** Style override for the value text. */
52
+ valueStyle?: StyleProp<TextStyle>;
53
+ /** Style override for the label text. */
54
+ labelStyle?: StyleProp<TextStyle>;
55
+ /** Style override for the circle view. */
56
+ circleStyle?: StyleProp<ViewStyle>;
57
+ /** Style override for the outer container. */
58
+ style?: StyleProp<ViewStyle>;
59
+ /** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
60
+ modes?: Record<string, any>;
61
+ /** Accessibility label. Defaults to a `value + label` composite. */
62
+ accessibilityLabel?: string;
63
+ };
64
+ /**
65
+ * `ClusterBubble` is the atomic circle that composes a `BubbleChart`. It renders
66
+ * a single token-colored disc with a bold `value` and a secondary `label`. The
67
+ * text can sit inside the circle or anchor just outside its edge on any side
68
+ * (`labelDirection`) at a precise `labelGap` distance — so consumers (or the
69
+ * chart) can steer labels toward free space. The inside text color adapts to
70
+ * the fill for legibility. It is fully usable standalone.
71
+ *
72
+ * @component
73
+ */
74
+ declare function ClusterBubble({ value, label, size, appearance, color, labelPlacement, labelDirection, labelGap, autoInsideMinSize, insideTextColor, onPress, valueStyle, labelStyle, circleStyle, style, modes: propModes, accessibilityLabel, }: ClusterBubbleProps): import("react/jsx-runtime").JSX.Element;
75
+ export default ClusterBubble;
76
+ //# sourceMappingURL=ClusterBubble.d.ts.map