@galaxy-io/dls 1.3.4 → 1.3.6

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.
@@ -34,10 +34,20 @@ import { styled } from "@linaria/react";
34
34
  * `min-width: 0` is load-bearing rather than cosmetic — without it a chart in a
35
35
  * flex row feeds its min-content width back into the ResizeObserver and the
36
36
  * measurement can oscillate.
37
+ *
38
+ * `$legendRight` rotates the layout: plot box and legend become a row with
39
+ * `align-items: center`, which is the whole of "the legend is vertically
40
+ * centred on the pie" — the pie is inscribed centred in its box, so centring
41
+ * the legend against the box centres it against the pie. It also holds in the
42
+ * other direction: a legend taller than the box centres the *pie* against the
43
+ * legend instead of pinning it to the top.
37
44
  */
38
45
  var _exp = () => ({ $fillWidth }) => $fillWidth ? "flex" : "inline-flex";
39
- var _exp2 = () => ({ $fillWidth }) => $fillWidth ? "100%" : "auto";
40
- var _exp3 = () => ({ $fillHeight }) => $fillHeight ? "100%" : "auto";
46
+ var _exp2 = () => ({ $legendRight }) => $legendRight ? "row" : "column";
47
+ var _exp3 = () => ({ $legendRight }) => $legendRight ? "center" : "stretch";
48
+ var _exp4 = () => ({ $legendRight }) => $legendRight ? "center" : "normal";
49
+ var _exp5 = () => ({ $fillWidth }) => $fillWidth ? "100%" : "auto";
50
+ var _exp6 = () => ({ $fillHeight }) => $fillHeight ? "100%" : "auto";
41
51
  var ChartRoot = /*#__PURE__*/ styled("div")({
42
52
  name: "ChartRoot",
43
53
  class: "c1hcga6s",
@@ -45,7 +55,10 @@ var ChartRoot = /*#__PURE__*/ styled("div")({
45
55
  vars: {
46
56
  "c1hcga6s-0": [_exp()],
47
57
  "c1hcga6s-1": [_exp2()],
48
- "c1hcga6s-2": [_exp3()]
58
+ "c1hcga6s-2": [_exp3()],
59
+ "c1hcga6s-3": [_exp4()],
60
+ "c1hcga6s-4": [_exp5()],
61
+ "c1hcga6s-5": [_exp6()]
49
62
  }
50
63
  });
51
64
  /**
@@ -64,19 +77,21 @@ var ChartRoot = /*#__PURE__*/ styled("div")({
64
77
  * `min-height: 0` is required with it: a flex item's automatic minimum size is
65
78
  * its content, which would let the SVG hold the box open above its track.
66
79
  */
67
- var _exp4 = () => ({ $reservedAspectRatio }) => $reservedAspectRatio ?? "auto";
68
- var _exp5 = () => ({ $reservedHeight }) => $reservedHeight ? `${$reservedHeight}px` : "auto";
69
- var _exp6 = () => ({ $fillHeight }) => $fillHeight ? "1 1 0%" : "0 1 auto";
70
- var _exp7 = () => ({ $fillHeight }) => $fillHeight ? "0" : "auto";
80
+ var _exp7 = () => ({ $legendRight }) => $legendRight ? "auto" : "100%";
81
+ var _exp8 = () => ({ $reservedAspectRatio, $squareFromHeight }) => $squareFromHeight ? "1" : $reservedAspectRatio ?? "auto";
82
+ var _exp9 = () => ({ $reservedHeight, $fillHeight, $legendRight }) => $fillHeight && $legendRight ? "100%" : $reservedHeight ? `${$reservedHeight}px` : "auto";
83
+ var _exp0 = () => ({ $fillHeight, $legendRight, $squareFromHeight }) => $legendRight ? $squareFromHeight ? "0 1 auto" : "1 1 auto" : $fillHeight ? "1 1 0%" : "0 1 auto";
84
+ var _exp1 = () => ({ $fillHeight }) => $fillHeight ? "0" : "auto";
71
85
  var ChartPlotBox = /*#__PURE__*/ styled("div")({
72
86
  name: "ChartPlotBox",
73
87
  class: "c1fvbgkp",
74
88
  propsAsIs: false,
75
89
  vars: {
76
- "c1fvbgkp-0": [_exp4()],
77
- "c1fvbgkp-1": [_exp5()],
78
- "c1fvbgkp-2": [_exp6()],
79
- "c1fvbgkp-3": [_exp7()]
90
+ "c1fvbgkp-0": [_exp7()],
91
+ "c1fvbgkp-1": [_exp8()],
92
+ "c1fvbgkp-2": [_exp9()],
93
+ "c1fvbgkp-3": [_exp0()],
94
+ "c1fvbgkp-4": [_exp1()]
80
95
  }
81
96
  });
82
97
  /**
@@ -123,29 +138,22 @@ var ChartArcPath = /*#__PURE__*/ styled("path")({
123
138
  propsAsIs: true
124
139
  });
125
140
  /**
126
- * Wrapper for the category target layer.
141
+ * Wraps the marks while the chart is loading.
127
142
  *
128
- * Exists to carry the focus-ring colour: the targets themselves are plain
129
- * `styled.x` because they receive refs (see the module note above), so they
130
- * cannot read the theme directly. Setting `color` here lets them use
131
- * `currentColor` and still take the token rather than inheriting whatever the
132
- * consumer's page happens to set.
133
- */
134
- var _exp11 = () => ({ theme }) => theme.color.border.selected;
135
- var ChartCategoryTargetLayer = withTheme(/*#__PURE__*/ styled("g")({
136
- name: "ChartCategoryTargetLayer",
137
- class: "c1wvzvu4",
138
- propsAsIs: true,
139
- vars: { "c1wvzvu4-0": [_exp11()] }
140
- }));
141
- /**
142
- * Shared by both target shapes.
143
+ * Only motion lives here — the slow pulse shared with `TextShimmer` and
144
+ * `AvatarShimmer`, so a loading chart breathes in step with every other
145
+ * skeleton on the page. Colour arrives through the series resolver like any
146
+ * other mark colour, which is what lets bars and arcs ghost by `fill` and
147
+ * lines by `stroke` without per-shape CSS here.
143
148
  *
144
- * The ring is a `stroke`, not an `outline`: `outline` on SVG elements is a late
145
- * arrival in WebKit and `outline-offset` behaves inconsistently across engines,
146
- * while a stroke on a transparent shape is universally supported — and it
147
- * traces a pie arc, which a rectangular outline could not.
149
+ * Under reduced motion the pulse pins at its midpoint rather than sitting at
150
+ * full strength, so the chart still reads as a placeholder and not as data.
148
151
  */
152
+ var ChartSkeletonGroup = /*#__PURE__*/ styled("g")({
153
+ name: "ChartSkeletonGroup",
154
+ class: "c1wvzvu4",
155
+ propsAsIs: true
156
+ });
149
157
  /**
150
158
  * Per-category hit target, rendered above the marks.
151
159
  *
@@ -153,6 +161,9 @@ var ChartCategoryTargetLayer = withTheme(/*#__PURE__*/ styled("g")({
153
161
  * bar is as easy to hover as a two-hundred-pixel one, and crossing between
154
162
  * segments inside a category fires no events at all — so the tooltip holds
155
163
  * still instead of chasing each segment.
164
+ *
165
+ * No cursor and no focus treatment: the target only previews on hover, and a
166
+ * pointer cursor would promise a click that does nothing.
156
167
  */
157
168
  var ChartHitTarget = /*#__PURE__*/ styled("rect")({
158
169
  name: "ChartHitTarget",
@@ -164,43 +175,37 @@ var ChartHitTarget = /*#__PURE__*/ styled("rect")({
164
175
  *
165
176
  * A pie has no category axis to band, so its targets are the arc shapes
166
177
  * themselves — drawn again, transparent, above the marks. That keeps hit
167
- * testing and focus identical across all three charts instead of the pie
168
- * hit-testing its visible arcs directly.
178
+ * testing identical across all three charts instead of the pie hit-testing its
179
+ * visible arcs directly.
169
180
  */
170
181
  var ChartHitTargetPath = /*#__PURE__*/ styled("path")({
171
182
  name: "ChartHitTargetPath",
172
183
  class: "cblgiyf",
173
184
  propsAsIs: true
174
185
  });
175
- /** Full-plot backdrop; clicking it clears a pinned category. */
176
- var ChartBackdrop = /*#__PURE__*/ styled("rect")({
177
- name: "ChartBackdrop",
178
- class: "c1lr03cc",
179
- propsAsIs: true
180
- });
181
186
  /**
182
187
  * Solid hairline rather than a dashed rule, and drawn at every tick including
183
188
  * zero — the line under the bars is what makes them read as resting on a
184
189
  * baseline.
185
190
  */
186
- var _exp14 = () => ({ theme }) => theme.color.border.primary;
191
+ var _exp16 = () => ({ theme }) => theme.color.border.primary;
187
192
  var ChartGridLine = withTheme(/*#__PURE__*/ styled("line")({
188
193
  name: "ChartGridLine",
189
- class: "cizy1s8",
194
+ class: "c1lr03cc",
190
195
  propsAsIs: true,
191
- vars: { "cizy1s8-0": [_exp14()] }
196
+ vars: { "c1lr03cc-0": [_exp16()] }
192
197
  }));
193
198
  /** Vertical rule marking the hovered category on a line chart. */
194
- var _exp15 = () => ({ theme }) => theme.color.border.secondary;
199
+ var _exp17 = () => ({ theme }) => theme.color.border.secondary;
195
200
  var ChartCursorLine = withTheme(/*#__PURE__*/ styled("line")({
196
201
  name: "ChartCursorLine",
197
- class: "c1ukq11d",
202
+ class: "cizy1s8",
198
203
  propsAsIs: true,
199
- vars: { "c1ukq11d-0": [_exp15()] }
204
+ vars: { "cizy1s8-0": [_exp17()] }
200
205
  }));
201
206
  var ChartAxisLabelBox = /*#__PURE__*/ styled("foreignObject")({
202
207
  name: "ChartAxisLabelBox",
203
- class: "cwcko2m",
208
+ class: "c1ukq11d",
204
209
  propsAsIs: true
205
210
  });
206
211
  /**
@@ -210,21 +215,21 @@ var ChartAxisLabelBox = /*#__PURE__*/ styled("foreignObject")({
210
215
  * than teleporting, and it stays mounted while hidden so the fade can actually
211
216
  * run — unmounting on hide is why a fade-out never appears.
212
217
  */
213
- var _exp16 = () => ({ $x }) => `${$x}px`;
214
- var _exp17 = () => ({ $y }) => `${$y}px`;
215
- var _exp20 = () => ({ theme }) => theme.color.border.primary;
216
- var _exp21 = () => ({ theme }) => theme.color.background.primary;
217
- var _exp22 = () => ({ $isVisible }) => $isVisible ? 1 : 0;
218
+ var _exp18 = () => ({ $x }) => `${$x}px`;
219
+ var _exp19 = () => ({ $y }) => `${$y}px`;
220
+ var _exp22 = () => ({ theme }) => theme.color.border.primary;
221
+ var _exp23 = () => ({ theme }) => theme.color.background.primary;
222
+ var _exp24 = () => ({ $isVisible }) => $isVisible ? 1 : 0;
218
223
  var ChartTooltipPositioner = withTheme(/*#__PURE__*/ styled("div")({
219
224
  name: "ChartTooltipPositioner",
220
- class: "cqwhvyz",
225
+ class: "cwcko2m",
221
226
  propsAsIs: false,
222
227
  vars: {
223
- "cqwhvyz-0": [_exp16()],
224
- "cqwhvyz-1": [_exp17()],
225
- "cqwhvyz-2": [_exp20()],
226
- "cqwhvyz-3": [_exp21()],
227
- "cqwhvyz-4": [_exp22()]
228
+ "cwcko2m-0": [_exp18()],
229
+ "cwcko2m-1": [_exp19()],
230
+ "cwcko2m-2": [_exp22()],
231
+ "cwcko2m-3": [_exp23()],
232
+ "cwcko2m-4": [_exp24()]
228
233
  }
229
234
  }));
230
235
  /**
@@ -235,32 +240,32 @@ var ChartTooltipPositioner = withTheme(/*#__PURE__*/ styled("div")({
235
240
  * of the DLS. `pointer-events: none` keeps it from stealing hover from the arc
236
241
  * behind it.
237
242
  */
238
- var _exp26 = () => ({ $centerX }) => `${$centerX}px`;
239
- var _exp27 = () => ({ $centerY }) => `${$centerY}px`;
240
- var _exp29 = () => ({ $diameter }) => `${$diameter}px`;
243
+ var _exp28 = () => ({ $centerX }) => `${$centerX}px`;
244
+ var _exp29 = () => ({ $centerY }) => `${$centerY}px`;
245
+ var _exp31 = () => ({ $diameter }) => `${$diameter}px`;
241
246
  var ChartCenterBox = /*#__PURE__*/ styled("div")({
242
247
  name: "ChartCenterBox",
243
- class: "c1iaray",
248
+ class: "cqwhvyz",
244
249
  propsAsIs: false,
245
250
  vars: {
246
- "c1iaray-0": [_exp26()],
247
- "c1iaray-1": [_exp27()],
248
- "c1iaray-2": [_exp29()]
251
+ "cqwhvyz-0": [_exp28()],
252
+ "cqwhvyz-1": [_exp29()],
253
+ "cqwhvyz-2": [_exp31()]
249
254
  }
250
255
  });
251
256
  /**
252
257
  * Sits slightly above centre, over where the bars would be, so the axes stay
253
258
  * legible underneath.
254
259
  */
255
- var _exp30 = () => ({ theme }) => theme.color.border.primary;
256
- var _exp31 = () => ({ theme }) => theme.color.background.tertiary;
260
+ var _exp32 = () => ({ theme }) => theme.color.border.primary;
261
+ var _exp33 = () => ({ theme }) => theme.color.background.tertiary;
257
262
  var ChartEmptyOverlay = withTheme(/*#__PURE__*/ styled("div")({
258
263
  name: "ChartEmptyOverlay",
259
- class: "cz6jod1",
264
+ class: "c1iaray",
260
265
  propsAsIs: false,
261
266
  vars: {
262
- "cz6jod1-0": [_exp30()],
263
- "cz6jod1-1": [_exp31()]
267
+ "c1iaray-0": [_exp32()],
268
+ "c1iaray-1": [_exp33()]
264
269
  }
265
270
  }));
266
271
  /**
@@ -272,34 +277,47 @@ var ChartEmptyOverlay = withTheme(/*#__PURE__*/ styled("div")({
272
277
  * the marks dim instantly while their legend entries sit through the full
273
278
  * {@link CHART_RESTORE_DELAY_MS}, and the two visibly fall out of step.
274
279
  */
275
- var _exp32 = () => ({ $inset }) => `${$inset}px`;
280
+ var _exp34 = () => ({ $vertical }) => $vertical ? "column" : "row";
281
+ var _exp35 = () => ({ $vertical }) => $vertical ? "nowrap" : "wrap";
282
+ var _exp36 = () => ({ $vertical }) => $vertical ? "flex-start" : "center";
283
+ var _exp37 = () => ({ $vertical }) => $vertical ? "8px" : "8px 16px";
284
+ var _exp38 = () => ({ $vertical }) => $vertical ? "0" : "10px";
285
+ var _exp39 = () => ({ $inset }) => `${$inset}px`;
276
286
  var ChartLegendRow = /*#__PURE__*/ styled("div")({
277
287
  name: "ChartLegendRow",
278
- class: "c1de5mqk",
288
+ class: "cz6jod1",
279
289
  propsAsIs: false,
280
- vars: { "c1de5mqk-0": [_exp32()] }
290
+ vars: {
291
+ "cz6jod1-0": [_exp34()],
292
+ "cz6jod1-1": [_exp35()],
293
+ "cz6jod1-2": [_exp36()],
294
+ "cz6jod1-3": [_exp37()],
295
+ "cz6jod1-4": [_exp38()],
296
+ "cz6jod1-5": [_exp39()]
297
+ }
281
298
  });
282
299
  /**
283
300
  * One legend entry, when the legend is interactive.
284
301
  *
285
- * A real `<button>` rather than a styled div: it is clickable, so it has to be
286
- * reachable and operable by keyboard. `aria-pressed` carries the pinned state
287
- * the only thing here a screen reader can truthfully announce, since the plot
288
- * itself is `role="img"` and its marks are not in the accessibility tree.
302
+ * A real `<button>` rather than a styled div so it sits in the tab order:
303
+ * focusing an entry previews its series exactly as hovering does, which is the
304
+ * one keyboard affordance the charts keep the plot itself is `role="img"` and
305
+ * its marks are not in the accessibility tree. Activating it does nothing;
306
+ * isolation follows the pointer or the focus and releases with it.
289
307
  *
290
308
  * Shares the mark opacity ramp via `data-state`, so an entry recedes in step
291
309
  * with the series it names.
292
310
  */
293
311
  var ChartLegendItemButton = /*#__PURE__*/ styled("button")({
294
312
  name: "ChartLegendItemButton",
295
- class: "cjirv6a",
313
+ class: "c1de5mqk",
296
314
  propsAsIs: false
297
315
  });
298
316
  /** The same row, when the legend is inert — no button semantics to announce. */
299
317
  var ChartLegendItemStatic = /*#__PURE__*/ styled("div")({
300
318
  name: "ChartLegendItemStatic",
301
- class: "c1armna5",
319
+ class: "cjirv6a",
302
320
  propsAsIs: false
303
321
  });
304
322
  //#endregion
305
- export { ChartArcPath, ChartAreaPath, ChartAxisLabelBox, ChartBackdrop, ChartBarPath, ChartCategoryTargetLayer, ChartCenterBox, ChartCursorLine, ChartEmptyOverlay, ChartGridLine, ChartHitTarget, ChartHitTargetPath, ChartLegendItemButton, ChartLegendItemStatic, ChartLegendRow, ChartLinePath, ChartPlotBox, ChartPlotGroup, ChartPointCircle, ChartRoot, ChartSvg, ChartTooltipPositioner };
323
+ export { ChartArcPath, ChartAreaPath, ChartAxisLabelBox, ChartBarPath, ChartCenterBox, ChartCursorLine, ChartEmptyOverlay, ChartGridLine, ChartHitTarget, ChartHitTargetPath, ChartLegendItemButton, ChartLegendItemStatic, ChartLegendRow, ChartLinePath, ChartPlotBox, ChartPlotGroup, ChartPointCircle, ChartRoot, ChartSkeletonGroup, ChartSvg, ChartTooltipPositioner };
@@ -34,6 +34,7 @@ var ChartTooltip = ({ model, containerWidth, containerHeight, anchorHalfWidth, p
34
34
  children: [/* @__PURE__ */ jsx(Text, {
35
35
  size: TextSize.BODY_SM,
36
36
  variant: TextVariant.TERTIARY,
37
+ isEllipsis: true,
37
38
  children: displayed.label
38
39
  }), /* @__PURE__ */ jsx(FlexWrapper, {
39
40
  direction: FlexDirection.COLUMN,
@@ -47,6 +48,7 @@ var ChartTooltip = ({ model, containerWidth, containerHeight, anchorHalfWidth, p
47
48
  children: [/* @__PURE__ */ jsxs(FlexWrapper, {
48
49
  alignItems: AlignItems.CENTER,
49
50
  gap: 6,
51
+ minWidth: 0,
50
52
  children: [/* @__PURE__ */ jsx(FlexItem, {
51
53
  shrink: 0,
52
54
  children: /* @__PURE__ */ jsx(Circle, {
@@ -58,10 +60,13 @@ var ChartTooltip = ({ model, containerWidth, containerHeight, anchorHalfWidth, p
58
60
  isEllipsis: true,
59
61
  children: row.label
60
62
  })]
61
- }), /* @__PURE__ */ jsx(Text, {
62
- size: TextSize.BODY_SM,
63
- weight: TextWeight.MEDIUM,
64
- children: row.formattedValue
63
+ }), /* @__PURE__ */ jsx(FlexItem, {
64
+ shrink: 0,
65
+ children: /* @__PURE__ */ jsx(Text, {
66
+ size: TextSize.BODY_SM,
67
+ weight: TextWeight.MEDIUM,
68
+ children: row.formattedValue
69
+ })
65
70
  })]
66
71
  }, row.key))
67
72
  })]
@@ -25,12 +25,6 @@ export type LineChartProps<TMetric extends string> = BaseCartesianChartProps & C
25
25
  strokeWidth?: number;
26
26
  /** Draw a vertical rule at the active category. @default true */
27
27
  showCursor?: boolean;
28
- /**
29
- * Notified when a category is pinned or unpinned by a click.
30
- *
31
- * The index is a position on the category axis.
32
- */
33
- onPinnedChange?: (categoryIndex: number | null) => void;
34
28
  };
35
29
  /**
36
30
  * Line chart over a categorical x-axis.
@@ -40,5 +34,5 @@ export type LineChartProps<TMetric extends string> = BaseCartesianChartProps & C
40
34
  * what a reader wants, and it avoids the proximity search a
41
35
  * nearest-point-to-cursor model needs.
42
36
  */
43
- declare const LineChart: <TMetric extends string>({ series, lines, categories, width, height, fillWidth, fillHeight, aspectRatio, margin, curve, strokeWidth, showCursor, valueUnit, valueFormatter, labelFormatter, valueDomain, categoryLabelMode, categoryAxisTitle, valueAxisTitle, showGrid, showLegend, noTooltip, tooltipRenderer, isLoading, contentWhenEmpty, ariaLabel, ariaDescription, onPinnedChange, }: LineChartProps<TMetric>) => import("react").JSX.Element;
37
+ declare const LineChart: <TMetric extends string>({ series, lines, categories, width, height, fillWidth, fillHeight, aspectRatio, margin, curve, strokeWidth, showCursor, valueUnit, valueFormatter, labelFormatter, valueDomain, categoryLabelMode, categoryAxisTitle, valueAxisTitle, showGrid, showLegend, noTooltip, tooltipRenderer, isLoading, contentWhenEmpty, ariaLabel, ariaDescription, }: LineChartProps<TMetric>) => import("react").JSX.Element;
44
38
  export default LineChart;
@@ -1,10 +1,10 @@
1
1
  import { ChartKind, ChartTargetShape, LineChartCurve } from "./types.js";
2
- import { LINE_AREA_OPACITY, LINE_POINT_RADIUS } from "./constants.js";
2
+ import { LINE_AREA_OPACITY, LINE_POINT_RADIUS, SKELETON_LINE_SERIES } from "./constants.js";
3
3
  import { useSeriesColorResolver } from "./useSeriesColorResolver.js";
4
4
  import { useChartInteraction } from "./useChartInteraction.js";
5
5
  import { useCartesianChartLayout } from "./useCartesianChartLayout.js";
6
6
  import { buildLineChartGeometry, getLineValueDomain } from "./lineChartGeometry.js";
7
- import { ChartAreaPath, ChartCursorLine, ChartLinePath, ChartPointCircle } from "./ChartPrimitives.js";
7
+ import { ChartAreaPath, ChartCursorLine, ChartLinePath, ChartPointCircle, ChartSkeletonGroup } from "./ChartPrimitives.js";
8
8
  import ChartFrame from "./ChartFrame.js";
9
9
  import { ChartCategoryAxis, ChartValueAxis } from "./ChartAxis.js";
10
10
  import { useCallback, useMemo, useRef } from "react";
@@ -18,12 +18,30 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
18
  * what a reader wants, and it avoids the proximity search a
19
19
  * nearest-point-to-cursor model needs.
20
20
  */
21
- var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeight, aspectRatio, margin, curve = LineChartCurve.SMOOTH, strokeWidth, showCursor = true, valueUnit, valueFormatter, labelFormatter, valueDomain, categoryLabelMode, categoryAxisTitle, valueAxisTitle, showGrid = true, showLegend = true, noTooltip = false, tooltipRenderer, isLoading = false, contentWhenEmpty, ariaLabel, ariaDescription, onPinnedChange }) => {
21
+ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeight, aspectRatio, margin, curve = LineChartCurve.SMOOTH, strokeWidth, showCursor = true, valueUnit, valueFormatter, labelFormatter, valueDomain, categoryLabelMode, categoryAxisTitle, valueAxisTitle, showGrid = true, showLegend = true, noTooltip = false, tooltipRenderer, isLoading = false, contentWhenEmpty, ariaLabel, ariaDescription }) => {
22
22
  const containerRef = useRef(null);
23
23
  const colors = useSeriesColorResolver(series);
24
+ /**
25
+ * The data actually rendered: the caller's, or ghost lines while loading.
26
+ *
27
+ * Loading replaces the chart wholesale with skeleton data pushed through the
28
+ * real geometry pipeline — offset lines drawn with their area fills, so the
29
+ * placeholder has the layered depth of a real multi-series chart. The cast is
30
+ * safe because nothing derived from it ever surfaces: labels are hidden,
31
+ * targets are off, the legend shows stubs, and the accessible name says
32
+ * "loading" instead of counting.
33
+ */
34
+ const displayLines = useMemo(() => isLoading ? SKELETON_LINE_SERIES.map((values, lineIndex) => ({
35
+ metric: `skeleton-${lineIndex}`,
36
+ showArea: true,
37
+ points: values.map((value, index) => ({
38
+ x: `skeleton-${index}`,
39
+ y: value
40
+ }))
41
+ })) : lines, [isLoading, lines]);
24
42
  const { dimensions, domain, valueTicks, formatValue, formatLabel } = useCartesianChartLayout({
25
43
  containerRef,
26
- rawDomain: useMemo(() => getLineValueDomain(lines), [lines]),
44
+ rawDomain: useMemo(() => getLineValueDomain(displayLines), [displayLines]),
27
45
  valueDomain,
28
46
  width,
29
47
  height,
@@ -38,10 +56,10 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
38
56
  categoryAxisTitle
39
57
  });
40
58
  const { plotWidth, plotHeight } = dimensions;
41
- const resolveColor = useCallback(({ metric }) => colors.resolve(metric), [colors]);
59
+ const resolveColor = useCallback(({ metric }) => isLoading ? colors.placeholder : colors.resolve(metric), [colors, isLoading]);
42
60
  const geometry = useMemo(() => buildLineChartGeometry({
43
- lines,
44
- categories,
61
+ lines: displayLines,
62
+ categories: isLoading ? void 0 : categories,
45
63
  plotWidth,
46
64
  plotHeight,
47
65
  curve,
@@ -49,7 +67,8 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
49
67
  strokeWidth,
50
68
  resolveColor
51
69
  }), [
52
- lines,
70
+ displayLines,
71
+ isLoading,
53
72
  categories,
54
73
  plotWidth,
55
74
  plotHeight,
@@ -58,7 +77,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
58
77
  strokeWidth,
59
78
  resolveColor
60
79
  ]);
61
- const isEmpty = geometry.categories.length === 0 || lines.length === 0;
80
+ const isEmpty = geometry.categories.length === 0 || displayLines.length === 0;
62
81
  const legendItems = useMemo(() => colors.keys.map((metric) => ({
63
82
  key: metric,
64
83
  label: series[metric].label,
@@ -68,9 +87,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
68
87
  const interaction = useChartInteraction({
69
88
  categoryCount: geometry.columns.length,
70
89
  seriesKeys: legendKeys,
71
- disabled: noTooltip || isLoading || isEmpty,
72
- isLoading,
73
- onPinnedChange
90
+ disabled: noTooltip || isLoading || isEmpty
74
91
  });
75
92
  const activeColumn = interaction.activeIndex === null ? null : geometry.columns[interaction.activeIndex];
76
93
  const buildCategoryTooltip = useCallback((index) => {
@@ -104,7 +121,42 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
104
121
  width: column.bandWidth,
105
122
  height: plotHeight
106
123
  })), [geometry.columns, plotHeight]);
107
- return /* @__PURE__ */ jsxs(ChartFrame, {
124
+ const marks = /* @__PURE__ */ jsxs(Fragment, { children: [
125
+ geometry.paths.map((linePath) => linePath.areaPath ? /* @__PURE__ */ jsx(ChartAreaPath, {
126
+ d: linePath.areaPath,
127
+ fill: linePath.color,
128
+ fillOpacity: LINE_AREA_OPACITY,
129
+ "data-state": interaction.getMarkState({ seriesKey: linePath.metric })
130
+ }, `${linePath.id}:area`) : null),
131
+ showCursor && activeColumn && /* @__PURE__ */ jsx(ChartCursorLine, {
132
+ x1: activeColumn.x,
133
+ x2: activeColumn.x,
134
+ y1: 0,
135
+ y2: plotHeight
136
+ }),
137
+ geometry.paths.map((linePath) => /* @__PURE__ */ jsx(ChartLinePath, {
138
+ d: linePath.path,
139
+ stroke: linePath.color,
140
+ strokeWidth: linePath.strokeWidth,
141
+ strokeDasharray: linePath.dashArray,
142
+ "data-state": interaction.getMarkState({ seriesKey: linePath.metric })
143
+ }, linePath.id)),
144
+ geometry.isolatedPoints.map((point) => /* @__PURE__ */ jsx(ChartPointCircle, {
145
+ cx: point.x,
146
+ cy: point.y,
147
+ r: LINE_POINT_RADIUS,
148
+ fill: point.color,
149
+ "data-state": interaction.getMarkState({ seriesKey: point.metric })
150
+ }, `${point.id}:isolated`)),
151
+ activeColumn?.points.map((point) => /* @__PURE__ */ jsx(ChartPointCircle, {
152
+ cx: point.x,
153
+ cy: point.y,
154
+ r: LINE_POINT_RADIUS,
155
+ fill: point.color,
156
+ "data-state": interaction.getMarkState({ seriesKey: point.metric })
157
+ }, point.id))
158
+ ] });
159
+ return /* @__PURE__ */ jsx(ChartFrame, {
108
160
  containerRef,
109
161
  dimensions,
110
162
  fillWidth,
@@ -122,6 +174,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
122
174
  marginLeft: dimensions.margin.left,
123
175
  formatter: formatValue,
124
176
  showGrid,
177
+ showLabels: !isLoading,
125
178
  title: valueAxisTitle
126
179
  }), /* @__PURE__ */ jsx(ChartCategoryAxis, {
127
180
  labels: geometry.categories,
@@ -131,6 +184,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
131
184
  plotHeight,
132
185
  formatter: formatLabel,
133
186
  mode: categoryLabelMode,
187
+ showLabels: !isLoading,
134
188
  title: categoryAxisTitle
135
189
  })] }),
136
190
  noTooltip,
@@ -143,41 +197,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
143
197
  contentWhenEmpty,
144
198
  showLegend,
145
199
  legendItems,
146
- children: [
147
- geometry.paths.map((linePath) => linePath.areaPath ? /* @__PURE__ */ jsx(ChartAreaPath, {
148
- d: linePath.areaPath,
149
- fill: linePath.color,
150
- fillOpacity: LINE_AREA_OPACITY,
151
- "data-state": interaction.getMarkState({ seriesKey: linePath.metric })
152
- }, `${linePath.id}:area`) : null),
153
- showCursor && activeColumn && /* @__PURE__ */ jsx(ChartCursorLine, {
154
- x1: activeColumn.x,
155
- x2: activeColumn.x,
156
- y1: 0,
157
- y2: plotHeight
158
- }),
159
- geometry.paths.map((linePath) => /* @__PURE__ */ jsx(ChartLinePath, {
160
- d: linePath.path,
161
- stroke: linePath.color,
162
- strokeWidth: linePath.strokeWidth,
163
- strokeDasharray: linePath.dashArray,
164
- "data-state": interaction.getMarkState({ seriesKey: linePath.metric })
165
- }, linePath.id)),
166
- geometry.isolatedPoints.map((point) => /* @__PURE__ */ jsx(ChartPointCircle, {
167
- cx: point.x,
168
- cy: point.y,
169
- r: LINE_POINT_RADIUS,
170
- fill: point.color,
171
- "data-state": interaction.getMarkState({ seriesKey: point.metric })
172
- }, `${point.id}:isolated`)),
173
- activeColumn?.points.map((point) => /* @__PURE__ */ jsx(ChartPointCircle, {
174
- cx: point.x,
175
- cy: point.y,
176
- r: LINE_POINT_RADIUS,
177
- fill: point.color,
178
- "data-state": interaction.getMarkState({ seriesKey: point.metric })
179
- }, point.id))
180
- ]
200
+ children: isLoading ? /* @__PURE__ */ jsx(ChartSkeletonGroup, { children: marks }) : marks
181
201
  });
182
202
  };
183
203
  //#endregion
@@ -32,13 +32,6 @@ export type PieChartProps<TSlice extends string> = BaseChartProps & ChartSize &
32
32
  * Ignored when `innerRadiusRatio` is 0.
33
33
  */
34
34
  centerContent?: ReactNode;
35
- /**
36
- * Notified when a slice is pinned or unpinned by a click.
37
- *
38
- * The index is a position in the *rendered* arcs, which excludes folded
39
- * slices and may include the aggregated bucket.
40
- */
41
- onPinnedChange?: (sliceIndex: number | null) => void;
42
35
  };
43
36
  /**
44
37
  * Pie and donut chart.
@@ -47,5 +40,5 @@ export type PieChartProps<TSlice extends string> = BaseChartProps & ChartSize &
47
40
  * each arc is its own target. Small slices are folded into an "Other" bucket by
48
41
  * default, which keeps every remaining arc large enough to actually hit.
49
42
  */
50
- declare const PieChart: <TSlice extends string>({ series, slices, width, height, fillWidth, fillHeight, aspectRatio, margin, innerRadiusRatio, padAngle, cornerRadius, minSliceShare, aggregatedLabel, centerContent, valueUnit, valueFormatter, labelFormatter, showLegend, noTooltip, tooltipRenderer, isLoading, contentWhenEmpty, ariaLabel, ariaDescription, onPinnedChange, }: PieChartProps<TSlice>) => import("react").JSX.Element;
43
+ declare const PieChart: <TSlice extends string>({ series, slices, width, height, fillWidth, fillHeight, aspectRatio, margin, innerRadiusRatio, padAngle, cornerRadius, minSliceShare, aggregatedLabel, centerContent, valueUnit, valueFormatter, labelFormatter, showLegend, noTooltip, tooltipRenderer, isLoading, contentWhenEmpty, ariaLabel, ariaDescription, }: PieChartProps<TSlice>) => import("react").JSX.Element;
51
44
  export default PieChart;