@galaxy-io/dls 1.3.0 → 1.3.2

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 (43) hide show
  1. package/dist/charts/BarChart.d.ts +3 -3
  2. package/dist/charts/BarChart.js +68 -104
  3. package/dist/charts/ChartCategoryTargets.d.ts +27 -0
  4. package/dist/charts/ChartCategoryTargets.js +75 -0
  5. package/dist/charts/ChartFrame.d.ts +34 -6
  6. package/dist/charts/ChartFrame.js +72 -15
  7. package/dist/charts/ChartPrimitives.d.ts +35 -0
  8. package/dist/charts/ChartPrimitives.js +75 -38
  9. package/dist/charts/ChartTooltip.d.ts +3 -3
  10. package/dist/charts/ChartTooltip.js +2 -2
  11. package/dist/charts/LineChart.js +47 -62
  12. package/dist/charts/PieChart.js +48 -26
  13. package/dist/charts/barChartGeometry.d.ts +66 -33
  14. package/dist/charts/barChartGeometry.js +7 -15
  15. package/dist/charts/barChartLegend.d.ts +25 -0
  16. package/dist/charts/barChartLegend.js +23 -0
  17. package/dist/charts/chartFormat.d.ts +9 -1
  18. package/dist/charts/chartFormat.js +13 -1
  19. package/dist/charts/chartScales.d.ts +58 -22
  20. package/dist/charts/chartScales.js +92 -38
  21. package/dist/charts/constants.d.ts +22 -6
  22. package/dist/charts/constants.js +22 -1
  23. package/dist/charts/lineChartGeometry.d.ts +53 -15
  24. package/dist/charts/lineChartGeometry.js +6 -15
  25. package/dist/charts/pieChartGeometry.d.ts +20 -8
  26. package/dist/charts/pieChartGeometry.js +3 -13
  27. package/dist/charts/types.d.ts +51 -145
  28. package/dist/charts/types.js +22 -3
  29. package/dist/charts/useCartesianChartLayout.d.ts +70 -0
  30. package/dist/charts/useCartesianChartLayout.js +56 -0
  31. package/dist/charts/useChartDimensions.d.ts +10 -3
  32. package/dist/charts/useChartDimensions.js +14 -4
  33. package/dist/charts/useChartInteraction.d.ts +13 -8
  34. package/dist/charts/useChartInteraction.js +7 -11
  35. package/dist/charts/useSeriesColorResolver.d.ts +37 -0
  36. package/dist/charts/useSeriesColorResolver.js +27 -0
  37. package/dist/inputs/DateInput.js +3 -3
  38. package/dist/inputs/MultiSelectInput.d.ts +3 -2
  39. package/dist/inputs/MultiSelectInput.js +8 -8
  40. package/dist/inputs/SelectInput.d.ts +4 -8
  41. package/dist/inputs/SelectInput.js +14 -20
  42. package/dist/styles.css +13 -11
  43. package/package.json +1 -1
@@ -154,13 +154,10 @@ export declare const PIE_TOOLTIP_ANCHOR_INSET = 8;
154
154
  * them communicates more than rendering each faithfully.
155
155
  */
156
156
  export declare const PIE_MIN_SLICE_SHARE = 0.02;
157
+ /** React key used for the bucket that absorbs slices below the fold threshold. */
158
+ export declare const AGGREGATED_SLICE_KEY = "__other__";
157
159
  /** Margin around a pie, which needs no axis gutters. */
158
- export declare const PIE_CHART_MARGIN: {
159
- top: number;
160
- right: number;
161
- bottom: number;
162
- left: number;
163
- };
160
+ export declare const PIE_CHART_MARGIN: ChartMargin;
164
161
  /**
165
162
  * Duration in ms for hover, dim and tooltip transitions.
166
163
  *
@@ -218,6 +215,25 @@ export declare const CHART_TOOLTIP_MAX_WIDTH = 320;
218
215
  export declare const CAPTION_CHAR_WIDTH_PX = 6.2;
219
216
  /** Ceiling for an auto-sized left margin, so a wide formatter can't eat the plot. */
220
217
  export declare const MAX_AUTO_MARGIN_LEFT = 96;
218
+ /**
219
+ * Floor for an auto-sized left margin.
220
+ *
221
+ * Enough for a two- or three-character tick plus {@link VALUE_AXIS_TICK_GAP}, so
222
+ * an axis labelled `0`–`5` still has its numbers clear of the container edge
223
+ * rather than jammed against it.
224
+ */
225
+ export declare const MIN_AUTO_MARGIN_LEFT = 32;
226
+ /**
227
+ * Quantum for an auto-sized left margin, in px.
228
+ *
229
+ * Sizing the gutter to the widest tick means the plot origin moves whenever that
230
+ * label's width changes — live data crossing 999 → 1000 gains a digit and would
231
+ * shift every mark sideways. Rounding up to a step absorbs that: the margin only
232
+ * moves when a label crosses a real threshold, and two charts with similar ticks
233
+ * land on the *same* value, so stacked charts in a dashboard keep their plots
234
+ * aligned instead of each choosing its own origin.
235
+ */
236
+ export declare const AUTO_MARGIN_LEFT_STEP = 8;
221
237
  /** Minimum px between category labels before AUTO mode starts skipping them. */
222
238
  export declare const MIN_CATEGORY_LABEL_GAP = 8;
223
239
  /**
@@ -159,6 +159,8 @@ var PIE_TOOLTIP_ANCHOR_INSET = 8;
159
159
  * them communicates more than rendering each faithfully.
160
160
  */
161
161
  var PIE_MIN_SLICE_SHARE = .02;
162
+ /** React key used for the bucket that absorbs slices below the fold threshold. */
163
+ var AGGREGATED_SLICE_KEY = "__other__";
162
164
  /** Margin around a pie, which needs no axis gutters. */
163
165
  var PIE_CHART_MARGIN = {
164
166
  top: 8,
@@ -223,6 +225,25 @@ var CHART_TOOLTIP_MAX_WIDTH = 320;
223
225
  var CAPTION_CHAR_WIDTH_PX = 6.2;
224
226
  /** Ceiling for an auto-sized left margin, so a wide formatter can't eat the plot. */
225
227
  var MAX_AUTO_MARGIN_LEFT = 96;
228
+ /**
229
+ * Floor for an auto-sized left margin.
230
+ *
231
+ * Enough for a two- or three-character tick plus {@link VALUE_AXIS_TICK_GAP}, so
232
+ * an axis labelled `0`–`5` still has its numbers clear of the container edge
233
+ * rather than jammed against it.
234
+ */
235
+ var MIN_AUTO_MARGIN_LEFT = 32;
236
+ /**
237
+ * Quantum for an auto-sized left margin, in px.
238
+ *
239
+ * Sizing the gutter to the widest tick means the plot origin moves whenever that
240
+ * label's width changes — live data crossing 999 → 1000 gains a digit and would
241
+ * shift every mark sideways. Rounding up to a step absorbs that: the margin only
242
+ * moves when a label crosses a real threshold, and two charts with similar ticks
243
+ * land on the *same* value, so stacked charts in a dashboard keep their plots
244
+ * aligned instead of each choosing its own origin.
245
+ */
246
+ var AUTO_MARGIN_LEFT_STEP = 8;
226
247
  /** Minimum px between category labels before AUTO mode starts skipping them. */
227
248
  var MIN_CATEGORY_LABEL_GAP = 8;
228
249
  /**
@@ -243,4 +264,4 @@ var CHART_PALETTE_ORDER = [
243
264
  ChartPalette.RED
244
265
  ];
245
266
  //#endregion
246
- export { AXIS_TITLE_BAND, AXIS_TITLE_GAP, BAR_GAP_COMFORTABLE, BAR_GAP_MEDIUM, BAR_GAP_TIGHT, BAR_RADIUS, BAR_RADIUS_NARROW, BAR_WIDTH_RATIO, CAPTION_CHAR_WIDTH_PX, CATEGORY_AXIS_LABEL_GAP, CATEGORY_AXIS_LABEL_HEIGHT, CHART_MARK_OPACITY_ACTIVE, CHART_MARK_OPACITY_FADED, CHART_MARK_OPACITY_MUTED, CHART_PALETTE_ORDER, CHART_RESTORE_DELAY_MS, CHART_TOOLTIP_MAX_WIDTH, CHART_TOOLTIP_MIN_WIDTH, CHART_TOOLTIP_OFFSET, CHART_TRANSITION_MS, DEFAULT_CHART_MARGIN, DEFAULT_LINE_STROKE_WIDTH, DEFAULT_VALUE_TICK_COUNT, GRID_LINE_BLEED, GROUP_GAP_COMFORTABLE, GROUP_GAP_MEDIUM, GROUP_GAP_TIGHT, LINE_AREA_OPACITY, LINE_POINT_RADIUS, MAX_AUTO_MARGIN_LEFT, MAX_BAR_WIDTH, MAX_GAP_SHARE, MIN_BARS_FOR_TIGHT_SPACING, MIN_BAR_LENGTH, MIN_CATEGORY_LABEL_GAP, NARROW_BAR_WIDTH, PIE_CHART_MARGIN, PIE_CORNER_RADIUS, PIE_DONUT_INNER_RATIO, PIE_MAX_AUTO_INNER_RATIO, PIE_MAX_INSET_SHARE, PIE_MIN_SLICE_SHARE, PIE_PAD_ANGLE, PIE_TOOLTIP_ANCHOR_INSET, STACK_SEGMENT_GAP, VALUE_AXIS_LABEL_HEIGHT, VALUE_AXIS_TICK_GAP, WIDTH_FOR_MEDIUM_SPACING, WIDTH_FOR_TIGHT_SPACING };
267
+ export { AGGREGATED_SLICE_KEY, AUTO_MARGIN_LEFT_STEP, AXIS_TITLE_BAND, AXIS_TITLE_GAP, BAR_GAP_COMFORTABLE, BAR_GAP_MEDIUM, BAR_GAP_TIGHT, BAR_RADIUS, BAR_RADIUS_NARROW, BAR_WIDTH_RATIO, CAPTION_CHAR_WIDTH_PX, CATEGORY_AXIS_LABEL_GAP, CATEGORY_AXIS_LABEL_HEIGHT, CHART_MARK_OPACITY_ACTIVE, CHART_MARK_OPACITY_FADED, CHART_MARK_OPACITY_MUTED, CHART_PALETTE_ORDER, CHART_RESTORE_DELAY_MS, CHART_TOOLTIP_MAX_WIDTH, CHART_TOOLTIP_MIN_WIDTH, CHART_TOOLTIP_OFFSET, CHART_TRANSITION_MS, DEFAULT_CHART_MARGIN, DEFAULT_LINE_STROKE_WIDTH, DEFAULT_VALUE_TICK_COUNT, GRID_LINE_BLEED, GROUP_GAP_COMFORTABLE, GROUP_GAP_MEDIUM, GROUP_GAP_TIGHT, LINE_AREA_OPACITY, LINE_POINT_RADIUS, MAX_AUTO_MARGIN_LEFT, MAX_BAR_WIDTH, MAX_GAP_SHARE, MIN_AUTO_MARGIN_LEFT, MIN_BARS_FOR_TIGHT_SPACING, MIN_BAR_LENGTH, MIN_CATEGORY_LABEL_GAP, NARROW_BAR_WIDTH, PIE_CHART_MARGIN, PIE_CORNER_RADIUS, PIE_DONUT_INNER_RATIO, PIE_MAX_AUTO_INNER_RATIO, PIE_MAX_INSET_SHARE, PIE_MIN_SLICE_SHARE, PIE_PAD_ANGLE, PIE_TOOLTIP_ANCHOR_INSET, STACK_SEGMENT_GAP, VALUE_AXIS_LABEL_HEIGHT, VALUE_AXIS_TICK_GAP, WIDTH_FOR_MEDIUM_SPACING, WIDTH_FOR_TIGHT_SPACING };
@@ -1,17 +1,51 @@
1
- import { buildCategoryPointScale, buildValueScale } from "./chartScales";
1
+ import { buildValueScale } from "./chartScales";
2
2
  import { LineChartCurve } from "./types";
3
- import type { ChartValueDomain, LineChartColumn, LineChartLineDatum, LineChartPath, LineChartPoint } from "./types";
3
+ import type { LineChartLineDatum } from "./types";
4
+ /** Signed value domain across every line, ignoring gaps. */
5
+ export declare function getLineValueDomain<TMetric extends string>(lines: LineChartLineDatum<TMetric>[]): [number, number];
6
+ /** One line, resolved to SVG paths. */
7
+ export interface LineChartPath<TMetric extends string> {
8
+ /** React key. Equal to the metric, which is unique by construction. */
9
+ id: string;
10
+ metric: TMetric;
11
+ /** `d` for the stroke. Empty when the line has no plottable points. */
12
+ path: string;
13
+ /** `d` for the area fill. Present only when the line opted into an area. */
14
+ areaPath?: string;
15
+ /** Pre-serialised `stroke-dasharray`. Absent for a solid line. */
16
+ dashArray?: string;
17
+ strokeWidth: number;
18
+ color: string;
19
+ }
20
+ /** One point, resolved to pixels. */
21
+ export interface LineChartPoint<TMetric extends string> {
22
+ /** React key. `${metric}:${categoryIndex}`. */
23
+ id: string;
24
+ metric: TMetric;
25
+ value: number;
26
+ x: number;
27
+ y: number;
28
+ color: string;
29
+ }
4
30
  /**
5
- * The union of every line's categories, in first-seen order.
31
+ * One category column: the hit target and everything the tooltip needs.
6
32
  *
7
- * Lines are allowed to be sparse, so the axis cannot come from any single one
8
- * of them. An explicit `categories` list wins, and is worth supplying whenever
9
- * the data is gappy — inferring order from a union of incomplete series is
10
- * guesswork, and guessing wrong reorders time.
33
+ * Line charts hit-test by column rather than by proximity to a stroke, so the
34
+ * whole vertical band is a target and the tooltip reports every line at once.
11
35
  */
12
- export declare function getLineCategories<TMetric extends string>(lines: LineChartLineDatum<TMetric>[], explicit?: string[]): string[];
13
- /** Signed value domain across every line, ignoring gaps. */
14
- export declare function getLineValueDomain<TMetric extends string>(lines: LineChartLineDatum<TMetric>[]): [number, number];
36
+ export interface LineChartColumn<TMetric extends string> {
37
+ categoryIndex: number;
38
+ label: string;
39
+ /** x of the category tick. */
40
+ x: number;
41
+ /** Full-height hit target, tiling with its neighbours. */
42
+ bandX: number;
43
+ bandWidth: number;
44
+ /** Points present in this column, one per line that has a value here. */
45
+ points: LineChartPoint<TMetric>[];
46
+ /** Topmost point in the column — where the tooltip anchors. */
47
+ anchorY: number;
48
+ }
15
49
  export interface LineChartGeometry<TMetric extends string> {
16
50
  paths: LineChartPath<TMetric>[];
17
51
  columns: LineChartColumn<TMetric>[];
@@ -25,8 +59,6 @@ export interface LineChartGeometry<TMetric extends string> {
25
59
  isolatedPoints: LineChartPoint<TMetric>[];
26
60
  categories: string[];
27
61
  valueScale: ReturnType<typeof buildValueScale>;
28
- categoryScale: ReturnType<typeof buildCategoryPointScale>;
29
- baselineY: number;
30
62
  /**
31
63
  * Distance between category ticks.
32
64
  *
@@ -43,12 +75,18 @@ interface BuildLineChartGeometryArgs<TMetric extends string> {
43
75
  plotWidth: number;
44
76
  plotHeight: number;
45
77
  curve: LineChartCurve;
46
- valueDomain?: Partial<ChartValueDomain>;
78
+ /**
79
+ * The final value domain, already overridden, zeroed and niced.
80
+ *
81
+ * Resolved by the caller rather than here, because the left gutter is sized
82
+ * from the tick labels and therefore needs the domain before the plot — and
83
+ * hence this builder — exists.
84
+ */
85
+ domain: [number, number];
47
86
  strokeWidth?: number;
48
87
  resolveColor: (args: {
49
88
  metric: TMetric;
50
- lineIndex: number;
51
89
  }) => string;
52
90
  }
53
- export declare function buildLineChartGeometry<TMetric extends string>({ lines, categories: explicitCategories, plotWidth, plotHeight, curve, valueDomain, strokeWidth: defaultStrokeWidth, resolveColor, }: BuildLineChartGeometryArgs<TMetric>): LineChartGeometry<TMetric>;
91
+ export declare function buildLineChartGeometry<TMetric extends string>({ lines, categories: explicitCategories, plotWidth, plotHeight, curve, domain, strokeWidth: defaultStrokeWidth, resolveColor, }: BuildLineChartGeometryArgs<TMetric>): LineChartGeometry<TMetric>;
54
92
  export {};
@@ -1,6 +1,6 @@
1
1
  import { LineChartCurve } from "./types.js";
2
2
  import { DEFAULT_LINE_STROKE_WIDTH } from "./constants.js";
3
- import { applyDomainOverride, buildCategoryPointScale, buildValueScale, sanitizeValue } from "./chartScales.js";
3
+ import { buildCategoryPointScale, buildValueScale, sanitizeValue } from "./chartScales.js";
4
4
  import { match } from "ts-pattern";
5
5
  import { area, curveLinear, curveMonotoneX, curveStepAfter, line } from "d3-shape";
6
6
  //#region src/charts/lineChartGeometry.ts
@@ -44,9 +44,9 @@ function getLineValueDomain(lines) {
44
44
  }
45
45
  return [Math.min(0, min), Math.max(0, max)];
46
46
  }
47
- function buildLineChartGeometry({ lines, categories: explicitCategories, plotWidth, plotHeight, curve, valueDomain, strokeWidth: defaultStrokeWidth = DEFAULT_LINE_STROKE_WIDTH, resolveColor }) {
47
+ function buildLineChartGeometry({ lines, categories: explicitCategories, plotWidth, plotHeight, curve, domain, strokeWidth: defaultStrokeWidth = DEFAULT_LINE_STROKE_WIDTH, resolveColor }) {
48
48
  const categories = getLineCategories(lines, explicitCategories);
49
- const valueScale = buildValueScale(applyDomainOverride(getLineValueDomain(lines), valueDomain), [plotHeight, 0]);
49
+ const valueScale = buildValueScale(domain, [plotHeight, 0]);
50
50
  const categoryScale = buildCategoryPointScale(categories, [0, plotWidth]);
51
51
  const baselineY = valueScale(0);
52
52
  const paths = [];
@@ -58,19 +58,14 @@ function buildLineChartGeometry({ lines, categories: explicitCategories, plotWid
58
58
  isolatedPoints,
59
59
  categories,
60
60
  valueScale,
61
- categoryScale,
62
- baselineY,
63
61
  step: 0
64
62
  };
65
63
  const curveFactory = resolveCurve(curve);
66
64
  const categoryIndex = new Map(categories.map((label, index) => [label, index]));
67
65
  const xAt = (index) => categoryScale(categories[index]) ?? 0;
68
66
  const pointsByCategory = categories.map(() => []);
69
- lines.forEach((lineDatum, lineIndex) => {
70
- const color = resolveColor({
71
- metric: lineDatum.metric,
72
- lineIndex
73
- });
67
+ lines.forEach((lineDatum) => {
68
+ const color = resolveColor({ metric: lineDatum.metric });
74
69
  const stroke = lineDatum.strokeWidth ?? defaultStrokeWidth;
75
70
  const plotted = categories.map((_, index) => ({
76
71
  categoryIndex: index,
@@ -87,7 +82,6 @@ function buildLineChartGeometry({ lines, categories: explicitCategories, plotWid
87
82
  paths.push({
88
83
  id: lineDatum.metric,
89
84
  metric: lineDatum.metric,
90
- lineIndex,
91
85
  path: strokePath,
92
86
  areaPath,
93
87
  dashArray: lineDatum.dashSize ? `${lineDatum.dashSize} ${lineDatum.dashSize}` : void 0,
@@ -99,7 +93,6 @@ function buildLineChartGeometry({ lines, categories: explicitCategories, plotWid
99
93
  const point = {
100
94
  id: `${lineDatum.metric}:${p.categoryIndex}`,
101
95
  metric: lineDatum.metric,
102
- categoryIndex: p.categoryIndex,
103
96
  value: p.value,
104
97
  x: xAt(p.categoryIndex),
105
98
  y: valueScale(p.value),
@@ -134,10 +127,8 @@ function buildLineChartGeometry({ lines, categories: explicitCategories, plotWid
134
127
  isolatedPoints,
135
128
  categories,
136
129
  valueScale,
137
- categoryScale,
138
- baselineY,
139
130
  step
140
131
  };
141
132
  }
142
133
  //#endregion
143
- export { buildLineChartGeometry, getLineCategories, getLineValueDomain };
134
+ export { buildLineChartGeometry, getLineValueDomain };
@@ -1,4 +1,4 @@
1
- import type { ChartPalette, PieChartArc, PieChartSliceDatum } from "./types";
1
+ import type { ChartPalette, PieChartSliceDatum } from "./types";
2
2
  /**
3
3
  * Pie and donut geometry.
4
4
  *
@@ -7,14 +7,27 @@ import type { ChartPalette, PieChartArc, PieChartSliceDatum } from "./types";
7
7
  *
8
8
  * Pure: no React, no theme access. Colours arrive through a resolver callback.
9
9
  */
10
- export interface PieChartGeometry<TSlice extends string> {
11
- arcs: PieChartArc<TSlice>[];
12
- /** Sum of every sanitised value. Zero means there is nothing to draw. */
13
- total: number;
10
+ /** One rendered arc. */
11
+ export interface PieChartArc {
12
+ /** React key. The slice key, or `AGGREGATED_SLICE_KEY` for the folded bucket. */
13
+ id: string;
14
+ label: string;
15
+ /** Summed value for the aggregated bucket, the slice's own otherwise. */
16
+ value: number;
17
+ /** Share of the total, 0–1. */
18
+ share: number;
19
+ /** `d` for the arc. */
20
+ path: string;
21
+ /** Anchor for the tooltip, just outside the arc's outer edge. */
22
+ anchorX: number;
23
+ anchorY: number;
24
+ color: string;
25
+ }
26
+ export interface PieChartGeometry {
27
+ arcs: PieChartArc[];
14
28
  /** Centre of the pie, in plot coordinates. */
15
29
  centerX: number;
16
30
  centerY: number;
17
- outerRadius: number;
18
31
  innerRadius: number;
19
32
  }
20
33
  interface BuildPieChartGeometryArgs<TSlice extends string> {
@@ -37,12 +50,11 @@ interface BuildPieChartGeometryArgs<TSlice extends string> {
37
50
  aggregatedLabel?: string;
38
51
  resolveColor: (args: {
39
52
  sliceKey: TSlice | null;
40
- index: number;
41
53
  explicit?: ChartPalette;
42
54
  }) => string;
43
55
  /** Palette override declared by the caller for a given slice. */
44
56
  getSliceColor?: (sliceKey: TSlice) => ChartPalette | undefined;
45
57
  getSliceLabel: (sliceKey: TSlice) => string;
46
58
  }
47
- export declare function buildPieChartGeometry<TSlice extends string>({ slices, plotWidth, plotHeight, innerRadiusRatio, padAngle, cornerRadius, minSliceShare, aggregatedLabel, resolveColor, getSliceColor, getSliceLabel, }: BuildPieChartGeometryArgs<TSlice>): PieChartGeometry<TSlice>;
59
+ export declare function buildPieChartGeometry<TSlice extends string>({ slices, plotWidth, plotHeight, innerRadiusRatio, padAngle, cornerRadius, minSliceShare, aggregatedLabel, resolveColor, getSliceColor, getSliceLabel, }: BuildPieChartGeometryArgs<TSlice>): PieChartGeometry;
48
60
  export {};
@@ -1,5 +1,4 @@
1
- import { AGGREGATED_SLICE_KEY } from "./types.js";
2
- import { PIE_DONUT_INNER_RATIO, PIE_MAX_AUTO_INNER_RATIO, PIE_MAX_INSET_SHARE, PIE_PAD_ANGLE } from "./constants.js";
1
+ import { AGGREGATED_SLICE_KEY, PIE_DONUT_INNER_RATIO, PIE_MAX_AUTO_INNER_RATIO, PIE_MAX_INSET_SHARE, PIE_PAD_ANGLE } from "./constants.js";
3
2
  import { sanitizeValue } from "./chartScales.js";
4
3
  import { arc, pie } from "d3-shape";
5
4
  //#region src/charts/pieChartGeometry.ts
@@ -16,10 +15,8 @@ function buildPieChartGeometry({ slices, plotWidth, plotHeight, innerRadiusRatio
16
15
  const total = sanitized.reduce((sum, slice) => sum + slice.value, 0);
17
16
  const empty = {
18
17
  arcs: [],
19
- total,
20
18
  centerX,
21
19
  centerY,
22
- outerRadius,
23
20
  innerRadius: requestedInnerRadius
24
21
  };
25
22
  if (total <= 0 || outerRadius <= 0) return empty;
@@ -51,13 +48,12 @@ function buildPieChartGeometry({ slices, plotWidth, plotHeight, innerRadiusRatio
51
48
  const layout = pie().sort(null).value((slice) => slice.value).padAngle(padAngle);
52
49
  const arcGenerator = arc().innerRadius(innerRadius).outerRadius(outerRadius).cornerRadius(cornerRadius);
53
50
  return {
54
- arcs: layout(kept).map((slot, index) => {
51
+ arcs: layout(kept).map((slot) => {
55
52
  const slice = slot.data;
56
53
  const midAngle = (slot.startAngle + slot.endAngle) / 2;
57
54
  const anchorRadius = outerRadius + 8;
58
55
  return {
59
56
  id: slice.isAggregated ? AGGREGATED_SLICE_KEY : slice.sliceKey,
60
- sliceKey: slice.sliceKey,
61
57
  label: slice.label,
62
58
  value: slice.value,
63
59
  share: slice.value / total,
@@ -66,22 +62,16 @@ function buildPieChartGeometry({ slices, plotWidth, plotHeight, innerRadiusRatio
66
62
  endAngle: slot.endAngle,
67
63
  padAngle: slot.padAngle
68
64
  }) ?? "",
69
- startAngle: slot.startAngle,
70
- endAngle: slot.endAngle,
71
65
  anchorX: centerX + Math.sin(midAngle) * anchorRadius,
72
66
  anchorY: centerY - Math.cos(midAngle) * anchorRadius,
73
67
  color: resolveColor({
74
68
  sliceKey: slice.sliceKey,
75
- index,
76
69
  explicit: slice.explicit
77
- }),
78
- isAggregated: slice.isAggregated
70
+ })
79
71
  };
80
72
  }),
81
- total,
82
73
  centerX,
83
74
  centerY,
84
- outerRadius,
85
75
  innerRadius
86
76
  };
87
77
  }
@@ -108,6 +108,18 @@ export interface ChartValueDomain {
108
108
  /** Approximate tick count passed to d3's `scale.ticks()`. */
109
109
  tickCount: number;
110
110
  }
111
+ /**
112
+ * Which chart is being rendered.
113
+ *
114
+ * Exists so the frame can phrase a default accessible name — a pie has slices
115
+ * where the cartesian charts have categories. Deliberately not a styling hook:
116
+ * nothing else branches on it.
117
+ */
118
+ export declare enum ChartKind {
119
+ BAR = "BAR",
120
+ LINE = "LINE",
121
+ PIE = "PIE"
122
+ }
111
123
  /** How the category axis copes when labels outgrow their slots. */
112
124
  export declare enum ChartCategoryLabelMode {
113
125
  /** Render every label that fits; otherwise show every nth. The default. */
@@ -175,83 +187,20 @@ export interface BarChartComponentDatum<TComponentKey extends string = string> {
175
187
  /**
176
188
  * One bar within a group: a stack of components for a single metric.
177
189
  */
178
- export interface BarChartBarDatum<TMetric extends string, TPivot extends string = string, TComponentKey extends string = string> {
190
+ export interface BarChartBarDatum<TMetric extends string, TComponentKey extends string = string> {
179
191
  /** Which metric this bar represents, e.g. `"prospected"`. */
180
192
  metric: TMetric;
181
- /** Optional dimension the bar is split by, e.g. `"persona"`. */
182
- pivot?: TPivot;
183
193
  /** Segments of the bar, stacked in array order outward from the baseline. */
184
194
  components: BarChartComponentDatum<TComponentKey>[];
185
195
  }
186
196
  /**
187
197
  * One category on the x-axis, holding one bar per metric.
188
198
  */
189
- export interface BarChartGroupDatum<TMetric extends string, TPivot extends string = string, TComponentKey extends string = string> {
199
+ export interface BarChartGroupDatum<TMetric extends string, TComponentKey extends string = string> {
190
200
  /** Label rendered beneath this group on the category axis. */
191
201
  label: string;
192
202
  /** Bars in this group, rendered left to right in array order. */
193
- bars: BarChartBarDatum<TMetric, TPivot, TComponentKey>[];
194
- }
195
- /**
196
- * A single rendered rectangle.
197
- *
198
- * The geometry layer flattens the group/bar/component hierarchy into an array
199
- * of these, so rendering is a plain `.map()` with no nested loops or
200
- * accumulators in the component body.
201
- */
202
- export interface BarChartRect<TMetric extends string, TComponentKey extends string = string> {
203
- /**
204
- * React key: `${groupIndex}:${barIndex}:${componentKey}`.
205
- *
206
- * Deliberately index-based rather than label-based — group labels are free to
207
- * repeat, and duplicated keys would silently drop rectangles.
208
- */
209
- id: string;
210
- groupIndex: number;
211
- barIndex: number;
212
- metric: TMetric;
213
- componentKey: TComponentKey;
214
- /** The component's label, carried through for the tooltip. */
215
- label: string;
216
- /** The raw value, before any normalization. */
217
- value: number;
218
- /**
219
- * The `[from, to]` interval this segment occupies in value space.
220
- * Under {@link BarChartNormalization.PERCENT} this is normalized to 0–1.
221
- */
222
- valueRange: [number, number];
223
- x: number;
224
- y: number;
225
- width: number;
226
- height: number;
227
- /** Resolved from the theme — never a raw hex from consumer data. */
228
- color: string;
229
- /** Interior stack segments get {@link BarCorners.NONE}. */
230
- corners: BarCorners;
231
- /** Corner radius in px, reduced for narrow bars so the curve can't dominate. */
232
- radius: number;
233
- }
234
- /**
235
- * A category's invisible hit target and tooltip anchor.
236
- *
237
- * Hit testing happens per group rather than per rectangle: a two-pixel bar is
238
- * then exactly as hoverable as a two-hundred-pixel one, and moving the pointer
239
- * between segments inside one group fires nothing, so the tooltip stays put
240
- * instead of jumping between segment tops.
241
- */
242
- export interface BarChartGroupBand {
243
- groupIndex: number;
244
- label: string;
245
- /** Tiles edge to edge with its neighbours, so there are no dead gutters. */
246
- x: number;
247
- y: number;
248
- width: number;
249
- height: number;
250
- /** Group centre, at the top of its tallest bar. Stable while hovering. */
251
- anchorX: number;
252
- anchorY: number;
253
- /** True when every component in the group is zero or absent. */
254
- isEmpty: boolean;
203
+ bars: BarChartBarDatum<TMetric, TComponentKey>[];
255
204
  }
256
205
  /** How the segments between points are interpolated. */
257
206
  export declare enum LineChartCurve {
@@ -299,51 +248,6 @@ export interface LineChartLineDatum<TMetric extends string> {
299
248
  /** Fill the area between the line and the baseline. */
300
249
  showArea?: boolean;
301
250
  }
302
- /** One line, resolved to SVG paths. */
303
- export interface LineChartPath<TMetric extends string> {
304
- /** React key. Equal to the metric, which is unique by construction. */
305
- id: string;
306
- metric: TMetric;
307
- lineIndex: number;
308
- /** `d` for the stroke. Empty when the line has no plottable points. */
309
- path: string;
310
- /** `d` for the area fill. Present only when the line opted into an area. */
311
- areaPath?: string;
312
- /** Pre-serialised `stroke-dasharray`. Absent for a solid line. */
313
- dashArray?: string;
314
- strokeWidth: number;
315
- color: string;
316
- }
317
- /** One point, resolved to pixels. */
318
- export interface LineChartPoint<TMetric extends string> {
319
- /** React key. `${metric}:${categoryIndex}`. */
320
- id: string;
321
- metric: TMetric;
322
- categoryIndex: number;
323
- value: number;
324
- x: number;
325
- y: number;
326
- color: string;
327
- }
328
- /**
329
- * One category column: the hit target and everything the tooltip needs.
330
- *
331
- * Line charts hit-test by column rather than by proximity to a stroke, so the
332
- * whole vertical band is a target and the tooltip reports every line at once.
333
- */
334
- export interface LineChartColumn<TMetric extends string> {
335
- categoryIndex: number;
336
- label: string;
337
- /** x of the category tick. */
338
- x: number;
339
- /** Full-height hit target, tiling with its neighbours. */
340
- bandX: number;
341
- bandWidth: number;
342
- /** Points present in this column, one per line that has a value here. */
343
- points: LineChartPoint<TMetric>[];
344
- /** Topmost point in the column — where the tooltip anchors. */
345
- anchorY: number;
346
- }
347
251
  /**
348
252
  * One slice of a pie or donut.
349
253
  *
@@ -361,44 +265,12 @@ export interface PieChartSliceDatum<TSlice extends string> {
361
265
  */
362
266
  value: number;
363
267
  }
364
- /** React key used for the bucket that absorbs slices below the fold threshold. */
365
- export declare const AGGREGATED_SLICE_KEY = "__other__";
366
- /** One rendered arc. */
367
- export interface PieChartArc<TSlice extends string> {
368
- /** React key. The slice key, or {@link AGGREGATED_SLICE_KEY}. */
369
- id: string;
370
- /**
371
- * The originating slice, or `null` for the aggregated bucket.
372
- *
373
- * Nullable rather than widened to `string` so callers must acknowledge the
374
- * synthetic arc instead of accidentally treating it as a real slice key.
375
- */
376
- sliceKey: TSlice | null;
377
- label: string;
378
- /** Summed value for the aggregated bucket, the slice's own otherwise. */
379
- value: number;
380
- /** Share of the total, 0–1. */
381
- share: number;
382
- /** `d` for the arc. */
383
- path: string;
384
- /** Radians, clockwise from 12 o'clock. */
385
- startAngle: number;
386
- endAngle: number;
387
- /** Anchor for the tooltip, just outside the arc's outer edge. */
388
- anchorX: number;
389
- anchorY: number;
390
- color: string;
391
- /** True for the bucket produced by folding small slices together. */
392
- isAggregated: boolean;
393
- }
394
268
  /** One label/value row in the tooltip. */
395
269
  export interface ChartTooltipRow {
396
270
  /** React key, unique within the tooltip. */
397
271
  key: string;
398
272
  /** Row label — a component label, line label or slice label. */
399
273
  label: string;
400
- /** Optional grouping label, used when bars are split by a pivot. */
401
- group?: string;
402
274
  value: number;
403
275
  /** Already run through the resolved formatter. */
404
276
  formattedValue: string;
@@ -434,6 +306,33 @@ export interface ChartPlotTooltipModel {
434
306
  }
435
307
  /** Render prop for replacing the tooltip body. Positioning stays with the chart. */
436
308
  export type ChartTooltipRenderer = (model: ChartTooltipModel) => ReactNode;
309
+ /** Which shape a category's hit target is drawn as. */
310
+ export declare enum ChartTargetShape {
311
+ /** Cartesian charts: a full-height band over the category. */
312
+ RECT = "RECT",
313
+ /** Radial charts: the arc's own outline, redrawn transparent. */
314
+ PATH = "PATH"
315
+ }
316
+ /**
317
+ * One category's interactive target, in plot coordinates.
318
+ *
319
+ * Array position *is* the category index — already true of every geometry
320
+ * builder's output — so there is no index field that could fall out of step.
321
+ * `key` is carried separately because a pie's arcs reorder, where bar and line
322
+ * indices do not.
323
+ */
324
+ export type ChartCategoryTarget = {
325
+ key: string;
326
+ shape: ChartTargetShape.RECT;
327
+ x: number;
328
+ y: number;
329
+ width: number;
330
+ height: number;
331
+ } | {
332
+ key: string;
333
+ shape: ChartTargetShape.PATH;
334
+ d: string;
335
+ };
437
336
  /** One legend entry. */
438
337
  export interface ChartLegendItem {
439
338
  key: string;
@@ -500,7 +399,7 @@ export interface ChartFluidBothAxes {
500
399
  */
501
400
  export type ChartSize = ChartFixedSize | ChartFluidFixedHeight | ChartFluidRatioHeight | ChartFixedWidthFluidHeight | ChartFluidBothAxes;
502
401
  /**
503
- * Props common to every chart.
402
+ * Props common to every chart.
504
403
  *
505
404
  * Data props are declared per chart, since their shapes and generics differ.
506
405
  */
@@ -511,7 +410,14 @@ export interface BaseChartProps {
511
410
  valueUnit?: ChartValueUnit;
512
411
  /** Full control over value rendering. Wins over `valueUnit`. */
513
412
  valueFormatter?: ChartValueFormatter;
514
- /** Format category labels. Applied to the axis *and* the tooltip heading. */
413
+ /**
414
+ * Format category labels, wherever a category is named.
415
+ *
416
+ * That is the axis and the tooltip heading on the cartesian charts, and
417
+ * additionally the legend on a pie — whose legend lists *slices*, which are
418
+ * its categories. Bar and line legends name series, which come from the
419
+ * `series` record and are not categories, so this does not reach them.
420
+ */
515
421
  labelFormatter?: ChartLabelFormatter;
516
422
  /** Replace the tooltip body. Collision handling stays with the chart. */
517
423
  tooltipRenderer?: ChartTooltipRenderer;
@@ -67,6 +67,19 @@ var ChartValueUnit = /* @__PURE__ */ function(ChartValueUnit) {
67
67
  ChartValueUnit["COMPACT"] = "COMPACT";
68
68
  return ChartValueUnit;
69
69
  }({});
70
+ /**
71
+ * Which chart is being rendered.
72
+ *
73
+ * Exists so the frame can phrase a default accessible name — a pie has slices
74
+ * where the cartesian charts have categories. Deliberately not a styling hook:
75
+ * nothing else branches on it.
76
+ */
77
+ var ChartKind = /* @__PURE__ */ function(ChartKind) {
78
+ ChartKind["BAR"] = "BAR";
79
+ ChartKind["LINE"] = "LINE";
80
+ ChartKind["PIE"] = "PIE";
81
+ return ChartKind;
82
+ }({});
70
83
  /** How the category axis copes when labels outgrow their slots. */
71
84
  var ChartCategoryLabelMode = /* @__PURE__ */ function(ChartCategoryLabelMode) {
72
85
  /** Render every label that fits; otherwise show every nth. The default. */
@@ -130,7 +143,13 @@ var LineChartCurve = /* @__PURE__ */ function(LineChartCurve) {
130
143
  LineChartCurve["STEP"] = "STEP";
131
144
  return LineChartCurve;
132
145
  }({});
133
- /** React key used for the bucket that absorbs slices below the fold threshold. */
134
- var AGGREGATED_SLICE_KEY = "__other__";
146
+ /** Which shape a category's hit target is drawn as. */
147
+ var ChartTargetShape = /* @__PURE__ */ function(ChartTargetShape) {
148
+ /** Cartesian charts: a full-height band over the category. */
149
+ ChartTargetShape["RECT"] = "RECT";
150
+ /** Radial charts: the arc's own outline, redrawn transparent. */
151
+ ChartTargetShape["PATH"] = "PATH";
152
+ return ChartTargetShape;
153
+ }({});
135
154
  //#endregion
136
- export { AGGREGATED_SLICE_KEY, BarChartNormalization, BarCorners, ChartCategoryLabelMode, ChartMarkState, ChartPalette, ChartValueUnit, LineChartCurve };
155
+ export { BarChartNormalization, BarCorners, ChartCategoryLabelMode, ChartKind, ChartMarkState, ChartPalette, ChartTargetShape, ChartValueUnit, LineChartCurve };