@galaxy-io/dls 1.3.5 → 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.
@@ -1,10 +1,11 @@
1
1
  import { BarChartNormalization, ChartKind, ChartTargetShape } from "./types.js";
2
+ import { SKELETON_BAR_GROUPS } from "./constants.js";
2
3
  import { useSeriesColorResolver } from "./useSeriesColorResolver.js";
3
4
  import { useChartInteraction } from "./useChartInteraction.js";
4
5
  import { useCartesianChartLayout } from "./useCartesianChartLayout.js";
5
6
  import { getBarLegendItems } from "./barChartLegend.js";
6
7
  import { buildBarChartGeometry, getBarValueDomain, roundedRectPath } from "./barChartGeometry.js";
7
- import { ChartBarPath } from "./ChartPrimitives.js";
8
+ import { ChartBarPath, ChartSkeletonGroup } from "./ChartPrimitives.js";
8
9
  import ChartFrame from "./ChartFrame.js";
9
10
  import { ChartCategoryAxis, ChartValueAxis } from "./ChartAxis.js";
10
11
  import { useCallback, useMemo, useRef } from "react";
@@ -42,9 +43,29 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
42
43
  valueFormatter,
43
44
  valueUnit
44
45
  ]);
46
+ /**
47
+ * The data actually rendered: the caller's, or the skeleton's while loading.
48
+ *
49
+ * Loading replaces the chart wholesale with ghost bars pushed through the
50
+ * real geometry pipeline, so the skeleton gets the true radii and spacing.
51
+ * The cast is safe because nothing derived from skeleton data ever surfaces:
52
+ * labels are hidden, targets are off, the legend shows stubs, and the
53
+ * accessible name says "loading" instead of counting.
54
+ */
55
+ const displayGroups = useMemo(() => isLoading ? SKELETON_BAR_GROUPS.map((values, groupIndex) => ({
56
+ label: `skeleton-${groupIndex}`,
57
+ bars: values.map((value, barIndex) => ({
58
+ metric: `skeleton-${barIndex}`,
59
+ components: [{
60
+ key: "skeleton",
61
+ label: "",
62
+ value
63
+ }]
64
+ }))
65
+ })) : groups, [isLoading, groups]);
45
66
  const { dimensions, domain, valueTicks, formatValue, formatLabel, formatAxisValue } = useCartesianChartLayout({
46
67
  containerRef,
47
- rawDomain: useMemo(() => getBarValueDomain(groups, normalization), [groups, normalization]),
68
+ rawDomain: useMemo(() => getBarValueDomain(displayGroups, normalization), [displayGroups, normalization]),
48
69
  valueDomain,
49
70
  width,
50
71
  height,
@@ -69,10 +90,10 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
69
90
  * takes its metric's colour. Applying the metric colour to a stack would
70
91
  * paint every segment identically.
71
92
  */
72
- const isStacked = useMemo(() => groups.some((group) => group.bars.some((bar) => bar.components.length > 1)), [groups]);
73
- const resolveColor = useCallback(({ metric, componentIndex, isStacked: barIsStacked, explicit }) => barIsStacked ? colors.resolveByIndex(componentIndex, explicit) : colors.resolve(metric, explicit), [colors]);
93
+ const isStacked = useMemo(() => displayGroups.some((group) => group.bars.some((bar) => bar.components.length > 1)), [displayGroups]);
94
+ const resolveColor = useCallback(({ metric, componentIndex, isStacked: barIsStacked, explicit }) => isLoading ? colors.placeholder : barIsStacked ? colors.resolveByIndex(componentIndex, explicit) : colors.resolve(metric, explicit), [colors, isLoading]);
74
95
  const geometry = useMemo(() => buildBarChartGeometry({
75
- groups,
96
+ groups: displayGroups,
76
97
  plotWidth,
77
98
  plotHeight,
78
99
  normalization,
@@ -80,7 +101,7 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
80
101
  domain,
81
102
  resolveColor
82
103
  }), [
83
- groups,
104
+ displayGroups,
84
105
  plotWidth,
85
106
  plotHeight,
86
107
  normalization,
@@ -88,7 +109,7 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
88
109
  domain,
89
110
  resolveColor
90
111
  ]);
91
- const isEmpty = groups.length === 0;
112
+ const isEmpty = displayGroups.length === 0;
92
113
  const legendItems = useMemo(() => getBarLegendItems({
93
114
  isStacked,
94
115
  series,
@@ -104,8 +125,7 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
104
125
  const interaction = useChartInteraction({
105
126
  categoryCount: geometry.bands.length,
106
127
  seriesKeys: legendKeys,
107
- disabled: noTooltip || isLoading || isEmpty,
108
- isLoading
128
+ disabled: noTooltip || isLoading || isEmpty
109
129
  });
110
130
  const buildCategoryTooltip = useCallback((index) => {
111
131
  const band = geometry.bands[index];
@@ -140,6 +160,14 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
140
160
  width: band.width,
141
161
  height: band.height
142
162
  })), [geometry.bands]);
163
+ const marks = geometry.rects.map((rect) => /* @__PURE__ */ jsx(ChartBarPath, {
164
+ d: roundedRectPath(rect.x, rect.y, rect.width, rect.height, rect.radius, rect.corners),
165
+ fill: rect.color,
166
+ "data-state": interaction.getMarkState({
167
+ categoryIndex: rect.groupIndex,
168
+ seriesKey: isStacked ? rect.componentKey : rect.metric
169
+ })
170
+ }, rect.id));
143
171
  return /* @__PURE__ */ jsx(ChartFrame, {
144
172
  containerRef,
145
173
  dimensions,
@@ -158,15 +186,17 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
158
186
  marginLeft: dimensions.margin.left,
159
187
  formatter: formatAxisValue,
160
188
  showGrid,
189
+ showLabels: !isLoading,
161
190
  title: valueAxisTitle
162
191
  }), /* @__PURE__ */ jsx(ChartCategoryAxis, {
163
- labels: groups.map((group) => group.label),
192
+ labels: displayGroups.map((group) => group.label),
164
193
  positions: categoryPositions,
165
194
  step: categoryStep,
166
195
  plotWidth,
167
196
  plotHeight,
168
197
  formatter: formatLabel,
169
198
  mode: categoryLabelMode,
199
+ showLabels: !isLoading,
170
200
  title: categoryAxisTitle
171
201
  })] }),
172
202
  noTooltip,
@@ -179,14 +209,7 @@ var BarChart = ({ series, groups, width, height, fillWidth, fillHeight, aspectRa
179
209
  contentWhenEmpty,
180
210
  showLegend,
181
211
  legendItems,
182
- children: geometry.rects.map((rect) => /* @__PURE__ */ jsx(ChartBarPath, {
183
- d: roundedRectPath(rect.x, rect.y, rect.width, rect.height, rect.radius, rect.corners),
184
- fill: rect.color,
185
- "data-state": interaction.getMarkState({
186
- categoryIndex: rect.groupIndex,
187
- seriesKey: isStacked ? rect.componentKey : rect.metric
188
- })
189
- }, rect.id))
212
+ children: isLoading ? /* @__PURE__ */ jsx(ChartSkeletonGroup, { children: marks }) : marks
190
213
  });
191
214
  };
192
215
  //#endregion
@@ -22,6 +22,13 @@ interface ChartValueAxisProps {
22
22
  plotHeight: number;
23
23
  formatter: ChartValueFormatter;
24
24
  showGrid?: boolean;
25
+ /**
26
+ * Render the tick labels and title.
27
+ *
28
+ * Off while the chart is loading: the grid keeps the plot's structure, but
29
+ * numbers derived from placeholder data would read as data.
30
+ */
31
+ showLabels?: boolean;
25
32
  /**
26
33
  * Rotated title in the left gutter.
27
34
  *
@@ -30,7 +37,7 @@ interface ChartValueAxisProps {
30
37
  */
31
38
  title?: string;
32
39
  }
33
- export declare const ChartValueAxis: ({ ticks, scale, plotWidth, plotHeight, marginLeft, formatter, showGrid, title, }: ChartValueAxisProps) => import("react").JSX.Element;
40
+ export declare const ChartValueAxis: ({ ticks, scale, plotWidth, plotHeight, marginLeft, formatter, showGrid, showLabels, title, }: ChartValueAxisProps) => import("react").JSX.Element;
34
41
  interface ChartCategoryAxisProps {
35
42
  labels: string[];
36
43
  /** Left edge of each category's slot, in plot coordinates. */
@@ -42,6 +49,8 @@ interface ChartCategoryAxisProps {
42
49
  plotHeight: number;
43
50
  formatter: ChartLabelFormatter;
44
51
  mode?: ChartCategoryLabelMode;
52
+ /** Render the labels and title. Off while loading — see the value axis. */
53
+ showLabels?: boolean;
45
54
  /**
46
55
  * Title below the tick labels.
47
56
  *
@@ -49,5 +58,5 @@ interface ChartCategoryAxisProps {
49
58
  */
50
59
  title?: string;
51
60
  }
52
- export declare const ChartCategoryAxis: ({ labels, positions, step, plotWidth, plotHeight, formatter, mode, title, }: ChartCategoryAxisProps) => import("react").JSX.Element;
61
+ export declare const ChartCategoryAxis: ({ labels, positions, step, plotWidth, plotHeight, formatter, mode, showLabels, title, }: ChartCategoryAxisProps) => import("react").JSX.Element | null;
53
62
  export {};
@@ -6,7 +6,7 @@ import { getCategoryLabelStride } from "./chartScales.js";
6
6
  import { ChartAxisLabelBox, ChartGridLine } from "./ChartPrimitives.js";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  //#region src/charts/ChartAxis.tsx
9
- var ChartValueAxis = ({ ticks, scale, plotWidth, plotHeight, marginLeft, formatter, showGrid = true, title }) => {
9
+ var ChartValueAxis = ({ ticks, scale, plotWidth, plotHeight, marginLeft, formatter, showGrid = true, showLabels = true, title }) => {
10
10
  const titleBand = title ? 26 : 0;
11
11
  const labelWidth = Math.max(0, marginLeft - titleBand - 12);
12
12
  return /* @__PURE__ */ jsxs("g", {
@@ -18,7 +18,7 @@ var ChartValueAxis = ({ ticks, scale, plotWidth, plotHeight, marginLeft, formatt
18
18
  x2: plotWidth + 12,
19
19
  y1: 0,
20
20
  y2: 0
21
- }), labelWidth > 0 && /* @__PURE__ */ jsx(ChartAxisLabelBox, {
21
+ }), showLabels && labelWidth > 0 && /* @__PURE__ */ jsx(ChartAxisLabelBox, {
22
22
  x: -marginLeft + titleBand,
23
23
  y: -20 / 2,
24
24
  width: labelWidth,
@@ -37,7 +37,7 @@ var ChartValueAxis = ({ ticks, scale, plotWidth, plotHeight, marginLeft, formatt
37
37
  })
38
38
  })
39
39
  })]
40
- }, tick)), title && /* @__PURE__ */ jsx("g", {
40
+ }, tick)), showLabels && title && /* @__PURE__ */ jsx("g", {
41
41
  transform: `translate(${-marginLeft + 18 / 2}, ${plotHeight / 2}) rotate(-90)`,
42
42
  children: /* @__PURE__ */ jsx(ChartAxisLabelBox, {
43
43
  x: -plotHeight / 2,
@@ -61,7 +61,8 @@ var ChartValueAxis = ({ ticks, scale, plotWidth, plotHeight, marginLeft, formatt
61
61
  })]
62
62
  });
63
63
  };
64
- var ChartCategoryAxis = ({ labels, positions, step, plotWidth, plotHeight, formatter, mode = ChartCategoryLabelMode.AUTO, title }) => {
64
+ var ChartCategoryAxis = ({ labels, positions, step, plotWidth, plotHeight, formatter, mode = ChartCategoryLabelMode.AUTO, showLabels = true, title }) => {
65
+ if (!showLabels) return null;
65
66
  const formatted = labels.map(formatter);
66
67
  const stride = mode === ChartCategoryLabelMode.AUTO ? getCategoryLabelStride(formatted, step) : 1;
67
68
  const labelWidth = step * stride;
@@ -22,7 +22,8 @@ var ChartFrame = ({ containerRef, dimensions, fillWidth, fillHeight, interaction
22
22
  * showing three. The two charts previously counted different things for the
23
23
  * same situation, which is the drift this removes.
24
24
  */
25
- const resolvedAriaLabel = ariaLabel ?? match(kind).with(ChartKind.PIE, () => `Pie chart with ${categoryCount} slices`).with(ChartKind.BAR, () => `Bar chart with ${categoryCount} categories and ${legendItems.length} series`).with(ChartKind.LINE, () => `Line chart with ${categoryCount} categories and ${legendItems.length} series`).exhaustive();
25
+ const kindLabel = match(kind).with(ChartKind.PIE, () => "Pie").with(ChartKind.BAR, () => "Bar").with(ChartKind.LINE, () => "Line").exhaustive();
26
+ const resolvedAriaLabel = ariaLabel ?? (isLoading ? `${kindLabel} chart, loading` : match(kind).with(ChartKind.PIE, () => `Pie chart with ${categoryCount} slices`).with(ChartKind.BAR, () => `Bar chart with ${categoryCount} categories and ${legendItems.length} series`).with(ChartKind.LINE, () => `Line chart with ${categoryCount} categories and ${legendItems.length} series`).exhaustive());
26
27
  const tooltipModel = useMemo(() => noTooltip || interaction.activeIndex === null ? null : buildCategoryTooltip(interaction.activeIndex), [
27
28
  noTooltip,
28
29
  buildCategoryTooltip,
@@ -121,6 +122,7 @@ var ChartFrame = ({ containerRef, dimensions, fillWidth, fillHeight, interaction
121
122
  items: legendItems,
122
123
  inset: legendInset ?? (legendRight ? 16 : margin.left),
123
124
  vertical: legendRight,
125
+ isLoading,
124
126
  hoveredKey: interaction.hoveredSeriesKey,
125
127
  onItemEnter: interaction.onSeriesEnter,
126
128
  onItemLeave: interaction.onSeriesLeave
@@ -7,6 +7,14 @@ interface ChartLegendProps {
7
7
  hoveredKey?: string | null;
8
8
  /** Stack entries in a column — the side-placed layout. */
9
9
  vertical?: boolean;
10
+ /**
11
+ * Render shimmer stubs instead of items.
12
+ *
13
+ * Keeps the legend's space reserved while the chart shows its skeleton, so
14
+ * data arriving doesn't shift the layout — which matters most beside a pie,
15
+ * where the legend's width decides the plot box's.
16
+ */
17
+ isLoading?: boolean;
10
18
  /**
11
19
  * Supplying these makes the legend interactive. Omit them and it renders as
12
20
  * inert text, with no button semantics for a screen reader to announce.
@@ -25,5 +33,5 @@ interface ChartLegendProps {
25
33
  * Isolation only changes opacity, so the domain is untouched and the numbers
26
34
  * keep meaning what they did.
27
35
  */
28
- declare const ChartLegend: ({ items, inset, hoveredKey, vertical, onItemEnter, onItemLeave, }: ChartLegendProps) => import("react").JSX.Element | null;
36
+ declare const ChartLegend: ({ items, inset, hoveredKey, vertical, isLoading, onItemEnter, onItemLeave, }: ChartLegendProps) => import("react").JSX.Element | null;
29
37
  export default ChartLegend;
@@ -1,10 +1,21 @@
1
1
  import Text, { TextSize } from "../text/Text.js";
2
+ import TextShimmer from "../text/TextShimmer.js";
2
3
  import Circle from "../shapes/Circle.js";
3
4
  import { ChartMarkState } from "./types.js";
4
5
  import { ChartLegendItemButton, ChartLegendItemStatic, ChartLegendRow } from "./ChartPrimitives.js";
5
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/charts/ChartLegend.tsx
7
8
  /**
9
+ * Stub label widths in px, staggered so the placeholder reads as a legend
10
+ * rather than a repeated block. Three entries: enough to hold a legend's
11
+ * space without promising a series count.
12
+ */
13
+ var SKELETON_LABEL_WIDTHS = [
14
+ 40,
15
+ 56,
16
+ 48
17
+ ];
18
+ /**
8
19
  * Legend for the chart components.
9
20
  *
10
21
  * Hovering or focusing an entry isolates its series; leaving releases it.
@@ -15,7 +26,22 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
26
  * Isolation only changes opacity, so the domain is untouched and the numbers
16
27
  * keep meaning what they did.
17
28
  */
18
- var ChartLegend = ({ items, inset, hoveredKey = null, vertical = false, onItemEnter, onItemLeave }) => {
29
+ var ChartLegend = ({ items, inset, hoveredKey = null, vertical = false, isLoading = false, onItemEnter, onItemLeave }) => {
30
+ if (isLoading) return /* @__PURE__ */ jsx(ChartLegendRow, {
31
+ $inset: inset,
32
+ $vertical: vertical,
33
+ "data-active": "false",
34
+ children: SKELETON_LABEL_WIDTHS.map((labelWidth, index) => /* @__PURE__ */ jsxs(ChartLegendItemStatic, {
35
+ "data-state": ChartMarkState.ACTIVE,
36
+ children: [/* @__PURE__ */ jsx(TextShimmer, {
37
+ height: 8,
38
+ width: 8
39
+ }), /* @__PURE__ */ jsx(TextShimmer, {
40
+ height: 10,
41
+ width: labelWidth
42
+ })]
43
+ }, index))
44
+ });
19
45
  if (items.length === 0) return null;
20
46
  const isInteractive = Boolean(onItemEnter);
21
47
  const activeKey = hoveredKey;
@@ -55,6 +55,19 @@ export declare const ChartLinePath: import("@linaria/react").StyledComponent<imp
55
55
  export declare const ChartAreaPath: import("@linaria/react").StyledComponent<import("react").SVGProps<SVGPathElement> & Record<never, unknown>>;
56
56
  export declare const ChartPointCircle: import("@linaria/react").StyledComponent<import("react").SVGProps<SVGCircleElement> & Record<never, unknown>>;
57
57
  export declare const ChartArcPath: import("@linaria/react").StyledComponent<import("react").SVGProps<SVGPathElement> & Record<never, unknown>>;
58
+ /**
59
+ * Wraps the marks while the chart is loading.
60
+ *
61
+ * Only motion lives here — the slow pulse shared with `TextShimmer` and
62
+ * `AvatarShimmer`, so a loading chart breathes in step with every other
63
+ * skeleton on the page. Colour arrives through the series resolver like any
64
+ * other mark colour, which is what lets bars and arcs ghost by `fill` and
65
+ * lines by `stroke` without per-shape CSS here.
66
+ *
67
+ * Under reduced motion the pulse pins at its midpoint rather than sitting at
68
+ * full strength, so the chart still reads as a placeholder and not as data.
69
+ */
70
+ export declare const ChartSkeletonGroup: import("@linaria/react").StyledComponent<import("react").SVGProps<SVGGElement> & Record<never, unknown>>;
58
71
  /**
59
72
  * Per-category hit target, rendered above the marks.
60
73
  *
@@ -138,6 +138,23 @@ var ChartArcPath = /*#__PURE__*/ styled("path")({
138
138
  propsAsIs: true
139
139
  });
140
140
  /**
141
+ * Wraps the marks while the chart is loading.
142
+ *
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.
148
+ *
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.
151
+ */
152
+ var ChartSkeletonGroup = /*#__PURE__*/ styled("g")({
153
+ name: "ChartSkeletonGroup",
154
+ class: "c1wvzvu4",
155
+ propsAsIs: true
156
+ });
157
+ /**
141
158
  * Per-category hit target, rendered above the marks.
142
159
  *
143
160
  * Hit testing the full column rather than the bars themselves means a two-pixel
@@ -150,7 +167,7 @@ var ChartArcPath = /*#__PURE__*/ styled("path")({
150
167
  */
151
168
  var ChartHitTarget = /*#__PURE__*/ styled("rect")({
152
169
  name: "ChartHitTarget",
153
- class: "c1wvzvu4",
170
+ class: "c17guewt",
154
171
  propsAsIs: true
155
172
  });
156
173
  /**
@@ -163,7 +180,7 @@ var ChartHitTarget = /*#__PURE__*/ styled("rect")({
163
180
  */
164
181
  var ChartHitTargetPath = /*#__PURE__*/ styled("path")({
165
182
  name: "ChartHitTargetPath",
166
- class: "c17guewt",
183
+ class: "cblgiyf",
167
184
  propsAsIs: true
168
185
  });
169
186
  /**
@@ -171,24 +188,24 @@ var ChartHitTargetPath = /*#__PURE__*/ styled("path")({
171
188
  * zero — the line under the bars is what makes them read as resting on a
172
189
  * baseline.
173
190
  */
174
- var _exp15 = () => ({ theme }) => theme.color.border.primary;
191
+ var _exp16 = () => ({ theme }) => theme.color.border.primary;
175
192
  var ChartGridLine = withTheme(/*#__PURE__*/ styled("line")({
176
193
  name: "ChartGridLine",
177
- class: "cblgiyf",
194
+ class: "c1lr03cc",
178
195
  propsAsIs: true,
179
- vars: { "cblgiyf-0": [_exp15()] }
196
+ vars: { "c1lr03cc-0": [_exp16()] }
180
197
  }));
181
198
  /** Vertical rule marking the hovered category on a line chart. */
182
- var _exp16 = () => ({ theme }) => theme.color.border.secondary;
199
+ var _exp17 = () => ({ theme }) => theme.color.border.secondary;
183
200
  var ChartCursorLine = withTheme(/*#__PURE__*/ styled("line")({
184
201
  name: "ChartCursorLine",
185
- class: "c1lr03cc",
202
+ class: "cizy1s8",
186
203
  propsAsIs: true,
187
- vars: { "c1lr03cc-0": [_exp16()] }
204
+ vars: { "cizy1s8-0": [_exp17()] }
188
205
  }));
189
206
  var ChartAxisLabelBox = /*#__PURE__*/ styled("foreignObject")({
190
207
  name: "ChartAxisLabelBox",
191
- class: "cizy1s8",
208
+ class: "c1ukq11d",
192
209
  propsAsIs: true
193
210
  });
194
211
  /**
@@ -198,21 +215,21 @@ var ChartAxisLabelBox = /*#__PURE__*/ styled("foreignObject")({
198
215
  * than teleporting, and it stays mounted while hidden so the fade can actually
199
216
  * run — unmounting on hide is why a fade-out never appears.
200
217
  */
201
- var _exp17 = () => ({ $x }) => `${$x}px`;
202
- var _exp18 = () => ({ $y }) => `${$y}px`;
203
- var _exp21 = () => ({ theme }) => theme.color.border.primary;
204
- var _exp22 = () => ({ theme }) => theme.color.background.primary;
205
- var _exp23 = () => ({ $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;
206
223
  var ChartTooltipPositioner = withTheme(/*#__PURE__*/ styled("div")({
207
224
  name: "ChartTooltipPositioner",
208
- class: "c1ukq11d",
225
+ class: "cwcko2m",
209
226
  propsAsIs: false,
210
227
  vars: {
211
- "c1ukq11d-0": [_exp17()],
212
- "c1ukq11d-1": [_exp18()],
213
- "c1ukq11d-2": [_exp21()],
214
- "c1ukq11d-3": [_exp22()],
215
- "c1ukq11d-4": [_exp23()]
228
+ "cwcko2m-0": [_exp18()],
229
+ "cwcko2m-1": [_exp19()],
230
+ "cwcko2m-2": [_exp22()],
231
+ "cwcko2m-3": [_exp23()],
232
+ "cwcko2m-4": [_exp24()]
216
233
  }
217
234
  }));
218
235
  /**
@@ -223,32 +240,32 @@ var ChartTooltipPositioner = withTheme(/*#__PURE__*/ styled("div")({
223
240
  * of the DLS. `pointer-events: none` keeps it from stealing hover from the arc
224
241
  * behind it.
225
242
  */
226
- var _exp27 = () => ({ $centerX }) => `${$centerX}px`;
227
- var _exp28 = () => ({ $centerY }) => `${$centerY}px`;
228
- var _exp30 = () => ({ $diameter }) => `${$diameter}px`;
243
+ var _exp28 = () => ({ $centerX }) => `${$centerX}px`;
244
+ var _exp29 = () => ({ $centerY }) => `${$centerY}px`;
245
+ var _exp31 = () => ({ $diameter }) => `${$diameter}px`;
229
246
  var ChartCenterBox = /*#__PURE__*/ styled("div")({
230
247
  name: "ChartCenterBox",
231
- class: "cwcko2m",
248
+ class: "cqwhvyz",
232
249
  propsAsIs: false,
233
250
  vars: {
234
- "cwcko2m-0": [_exp27()],
235
- "cwcko2m-1": [_exp28()],
236
- "cwcko2m-2": [_exp30()]
251
+ "cqwhvyz-0": [_exp28()],
252
+ "cqwhvyz-1": [_exp29()],
253
+ "cqwhvyz-2": [_exp31()]
237
254
  }
238
255
  });
239
256
  /**
240
257
  * Sits slightly above centre, over where the bars would be, so the axes stay
241
258
  * legible underneath.
242
259
  */
243
- var _exp31 = () => ({ theme }) => theme.color.border.primary;
244
- var _exp32 = () => ({ theme }) => theme.color.background.tertiary;
260
+ var _exp32 = () => ({ theme }) => theme.color.border.primary;
261
+ var _exp33 = () => ({ theme }) => theme.color.background.tertiary;
245
262
  var ChartEmptyOverlay = withTheme(/*#__PURE__*/ styled("div")({
246
263
  name: "ChartEmptyOverlay",
247
- class: "cqwhvyz",
264
+ class: "c1iaray",
248
265
  propsAsIs: false,
249
266
  vars: {
250
- "cqwhvyz-0": [_exp31()],
251
- "cqwhvyz-1": [_exp32()]
267
+ "c1iaray-0": [_exp32()],
268
+ "c1iaray-1": [_exp33()]
252
269
  }
253
270
  }));
254
271
  /**
@@ -260,23 +277,23 @@ var ChartEmptyOverlay = withTheme(/*#__PURE__*/ styled("div")({
260
277
  * the marks dim instantly while their legend entries sit through the full
261
278
  * {@link CHART_RESTORE_DELAY_MS}, and the two visibly fall out of step.
262
279
  */
263
- var _exp33 = () => ({ $vertical }) => $vertical ? "column" : "row";
264
- var _exp34 = () => ({ $vertical }) => $vertical ? "nowrap" : "wrap";
265
- var _exp35 = () => ({ $vertical }) => $vertical ? "flex-start" : "center";
266
- var _exp36 = () => ({ $vertical }) => $vertical ? "8px" : "8px 16px";
267
- var _exp37 = () => ({ $vertical }) => $vertical ? "0" : "10px";
268
- var _exp38 = () => ({ $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`;
269
286
  var ChartLegendRow = /*#__PURE__*/ styled("div")({
270
287
  name: "ChartLegendRow",
271
- class: "c1iaray",
288
+ class: "cz6jod1",
272
289
  propsAsIs: false,
273
290
  vars: {
274
- "c1iaray-0": [_exp33()],
275
- "c1iaray-1": [_exp34()],
276
- "c1iaray-2": [_exp35()],
277
- "c1iaray-3": [_exp36()],
278
- "c1iaray-4": [_exp37()],
279
- "c1iaray-5": [_exp38()]
291
+ "cz6jod1-0": [_exp34()],
292
+ "cz6jod1-1": [_exp35()],
293
+ "cz6jod1-2": [_exp36()],
294
+ "cz6jod1-3": [_exp37()],
295
+ "cz6jod1-4": [_exp38()],
296
+ "cz6jod1-5": [_exp39()]
280
297
  }
281
298
  });
282
299
  /**
@@ -293,14 +310,14 @@ var ChartLegendRow = /*#__PURE__*/ styled("div")({
293
310
  */
294
311
  var ChartLegendItemButton = /*#__PURE__*/ styled("button")({
295
312
  name: "ChartLegendItemButton",
296
- class: "cz6jod1",
313
+ class: "c1de5mqk",
297
314
  propsAsIs: false
298
315
  });
299
316
  /** The same row, when the legend is inert — no button semantics to announce. */
300
317
  var ChartLegendItemStatic = /*#__PURE__*/ styled("div")({
301
318
  name: "ChartLegendItemStatic",
302
- class: "c1de5mqk",
319
+ class: "cjirv6a",
303
320
  propsAsIs: false
304
321
  });
305
322
  //#endregion
306
- export { ChartArcPath, ChartAreaPath, ChartAxisLabelBox, ChartBarPath, 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
  })]
@@ -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";
@@ -21,9 +21,27 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
21
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,8 +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
90
+ disabled: noTooltip || isLoading || isEmpty
73
91
  });
74
92
  const activeColumn = interaction.activeIndex === null ? null : geometry.columns[interaction.activeIndex];
75
93
  const buildCategoryTooltip = useCallback((index) => {
@@ -103,7 +121,42 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
103
121
  width: column.bandWidth,
104
122
  height: plotHeight
105
123
  })), [geometry.columns, plotHeight]);
106
- 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, {
107
160
  containerRef,
108
161
  dimensions,
109
162
  fillWidth,
@@ -121,6 +174,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
121
174
  marginLeft: dimensions.margin.left,
122
175
  formatter: formatValue,
123
176
  showGrid,
177
+ showLabels: !isLoading,
124
178
  title: valueAxisTitle
125
179
  }), /* @__PURE__ */ jsx(ChartCategoryAxis, {
126
180
  labels: geometry.categories,
@@ -130,6 +184,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
130
184
  plotHeight,
131
185
  formatter: formatLabel,
132
186
  mode: categoryLabelMode,
187
+ showLabels: !isLoading,
133
188
  title: categoryAxisTitle
134
189
  })] }),
135
190
  noTooltip,
@@ -142,41 +197,7 @@ var LineChart = ({ series, lines, categories, width, height, fillWidth, fillHeig
142
197
  contentWhenEmpty,
143
198
  showLegend,
144
199
  legendItems,
145
- children: [
146
- geometry.paths.map((linePath) => linePath.areaPath ? /* @__PURE__ */ jsx(ChartAreaPath, {
147
- d: linePath.areaPath,
148
- fill: linePath.color,
149
- fillOpacity: LINE_AREA_OPACITY,
150
- "data-state": interaction.getMarkState({ seriesKey: linePath.metric })
151
- }, `${linePath.id}:area`) : null),
152
- showCursor && activeColumn && /* @__PURE__ */ jsx(ChartCursorLine, {
153
- x1: activeColumn.x,
154
- x2: activeColumn.x,
155
- y1: 0,
156
- y2: plotHeight
157
- }),
158
- geometry.paths.map((linePath) => /* @__PURE__ */ jsx(ChartLinePath, {
159
- d: linePath.path,
160
- stroke: linePath.color,
161
- strokeWidth: linePath.strokeWidth,
162
- strokeDasharray: linePath.dashArray,
163
- "data-state": interaction.getMarkState({ seriesKey: linePath.metric })
164
- }, linePath.id)),
165
- geometry.isolatedPoints.map((point) => /* @__PURE__ */ jsx(ChartPointCircle, {
166
- cx: point.x,
167
- cy: point.y,
168
- r: LINE_POINT_RADIUS,
169
- fill: point.color,
170
- "data-state": interaction.getMarkState({ seriesKey: point.metric })
171
- }, `${point.id}:isolated`)),
172
- activeColumn?.points.map((point) => /* @__PURE__ */ jsx(ChartPointCircle, {
173
- cx: point.x,
174
- cy: point.y,
175
- r: LINE_POINT_RADIUS,
176
- fill: point.color,
177
- "data-state": interaction.getMarkState({ seriesKey: point.metric })
178
- }, point.id))
179
- ]
200
+ children: isLoading ? /* @__PURE__ */ jsx(ChartSkeletonGroup, { children: marks }) : marks
180
201
  });
181
202
  };
182
203
  //#endregion
@@ -1,13 +1,13 @@
1
1
  import FlexWrapper, { AlignItems, FlexDirection, JustifyContent } from "../containers/FlexWrapper.js";
2
2
  import { ChartKind, ChartLegendPlacement, ChartTargetShape } from "./types.js";
3
- import { PIE_CHART_MARGIN, PIE_MIN_SLICE_SHARE } from "./constants.js";
3
+ import { PIE_CHART_MARGIN, PIE_MIN_SLICE_SHARE, SKELETON_PIE_VALUES } from "./constants.js";
4
4
  import { useSeriesColorResolver } from "./useSeriesColorResolver.js";
5
5
  import { ChartTooltipVerticalAlign } from "./useChartTooltipPosition.js";
6
6
  import { useChartInteraction } from "./useChartInteraction.js";
7
7
  import { useChartFormatters } from "./useChartFormatters.js";
8
8
  import { useChartDimensions } from "./useChartDimensions.js";
9
9
  import { buildPieChartGeometry } from "./pieChartGeometry.js";
10
- import { ChartArcPath, ChartCenterBox } from "./ChartPrimitives.js";
10
+ import { ChartArcPath, ChartCenterBox, ChartSkeletonGroup } from "./ChartPrimitives.js";
11
11
  import ChartFrame from "./ChartFrame.js";
12
12
  import { useCallback, useMemo, useRef } from "react";
13
13
  import { jsx } from "react/jsx-runtime";
@@ -40,9 +40,23 @@ var PieChart = ({ series, slices, width, height, fillWidth, fillHeight, aspectRa
40
40
  });
41
41
  const getSliceLabel = useCallback((sliceKey) => series[sliceKey]?.label ?? sliceKey, [series]);
42
42
  const getSliceColor = useCallback((sliceKey) => series[sliceKey]?.color, [series]);
43
- const resolveColor = useCallback(({ sliceKey, explicit }) => sliceKey === null ? colors.neutral : colors.resolve(sliceKey, explicit), [colors]);
43
+ /**
44
+ * The slices actually rendered: the caller's, or three ghost arcs while
45
+ * loading, pushed through the real geometry so the skeleton donut gets the
46
+ * true pad angles and corner radii. The cast is safe because nothing derived
47
+ * from skeleton data ever surfaces: targets are off, the legend shows stubs,
48
+ * and the accessible name says "loading" instead of counting slices.
49
+ */
50
+ const displaySlices = useMemo(() => isLoading ? SKELETON_PIE_VALUES.map((value, index) => ({
51
+ key: `skeleton-${index}`,
52
+ value
53
+ })) : slices, [isLoading, slices]);
54
+ const resolveColor = useCallback(({ sliceKey, explicit }) => {
55
+ if (isLoading) return colors.placeholder;
56
+ return sliceKey === null ? colors.neutral : colors.resolve(sliceKey, explicit);
57
+ }, [colors, isLoading]);
44
58
  const geometry = useMemo(() => buildPieChartGeometry({
45
- slices,
59
+ slices: displaySlices,
46
60
  plotWidth,
47
61
  plotHeight,
48
62
  innerRadiusRatio,
@@ -54,7 +68,7 @@ var PieChart = ({ series, slices, width, height, fillWidth, fillHeight, aspectRa
54
68
  getSliceColor,
55
69
  getSliceLabel
56
70
  }), [
57
- slices,
71
+ displaySlices,
58
72
  plotWidth,
59
73
  plotHeight,
60
74
  innerRadiusRatio,
@@ -76,8 +90,7 @@ var PieChart = ({ series, slices, width, height, fillWidth, fillHeight, aspectRa
76
90
  const interaction = useChartInteraction({
77
91
  categoryCount: geometry.arcs.length,
78
92
  seriesKeys: legendKeys,
79
- disabled: noTooltip || isLoading || isEmpty,
80
- isLoading
93
+ disabled: noTooltip || isLoading || isEmpty
81
94
  });
82
95
  const buildCategoryTooltip = useCallback((index) => {
83
96
  const chartArc = geometry.arcs[index];
@@ -110,7 +123,18 @@ var PieChart = ({ series, slices, width, height, fillWidth, fillHeight, aspectRa
110
123
  shape: ChartTargetShape.PATH,
111
124
  d: chartArc.path
112
125
  })), [geometry.arcs]);
113
- const showCenter = centerContent && (innerRadiusRatio ?? .62) > 0;
126
+ const showCenter = centerContent && !isLoading && (innerRadiusRatio ?? .62) > 0;
127
+ const marks = /* @__PURE__ */ jsx("g", {
128
+ transform: `translate(${geometry.centerX}, ${geometry.centerY})`,
129
+ children: geometry.arcs.map((chartArc, index) => /* @__PURE__ */ jsx(ChartArcPath, {
130
+ d: chartArc.path,
131
+ fill: chartArc.color,
132
+ "data-state": interaction.getMarkState({
133
+ categoryIndex: index,
134
+ seriesKey: chartArc.id
135
+ })
136
+ }, chartArc.id))
137
+ });
114
138
  return /* @__PURE__ */ jsx(ChartFrame, {
115
139
  containerRef,
116
140
  dimensions,
@@ -140,17 +164,7 @@ var PieChart = ({ series, slices, width, height, fillWidth, fillHeight, aspectRa
140
164
  diameter: geometry.innerRadius * 2,
141
165
  children: centerContent
142
166
  }) : null,
143
- children: /* @__PURE__ */ jsx("g", {
144
- transform: `translate(${geometry.centerX}, ${geometry.centerY})`,
145
- children: geometry.arcs.map((chartArc, index) => /* @__PURE__ */ jsx(ChartArcPath, {
146
- d: chartArc.path,
147
- fill: chartArc.color,
148
- "data-state": interaction.getMarkState({
149
- categoryIndex: index,
150
- seriesKey: chartArc.id
151
- })
152
- }, chartArc.id))
153
- })
167
+ children: isLoading ? /* @__PURE__ */ jsx(ChartSkeletonGroup, { children: marks }) : marks
154
168
  });
155
169
  };
156
170
  /** Positions arbitrary content inside the donut hole. */
@@ -203,6 +203,25 @@ export declare const CHART_TOOLTIP_MIN_WIDTH = 168;
203
203
  export declare const CHART_TOOLTIP_MAX_WIDTH = 320;
204
204
  /** Gap in px between the plot box and a side-placed legend. */
205
205
  export declare const CHART_LEGEND_SIDE_GAP = 16;
206
+ /**
207
+ * Ghost bar heights, one inner array per group — three bars each, so the
208
+ * skeleton reads as the grouped chart it usually stands in for rather than a
209
+ * sparse row of lone bars.
210
+ */
211
+ export declare const SKELETON_BAR_GROUPS: number[][];
212
+ /**
213
+ * Ghost lines, one inner array per line, offset from each other and drawn with
214
+ * their area fills so the skeleton has the layered depth of a real multi-series
215
+ * chart instead of a single bare stroke.
216
+ */
217
+ export declare const SKELETON_LINE_SERIES: number[][];
218
+ /** Ghost donut shares — three arcs, halving. */
219
+ export declare const SKELETON_PIE_VALUES: number[];
220
+ /**
221
+ * Skeleton pulse period, matching the cadence of `TextShimmer` and
222
+ * `AvatarShimmer` so charts load in step with everything else on the page.
223
+ */
224
+ export declare const CHART_SKELETON_PULSE_MS = 2500;
206
225
  /**
207
226
  * Approximate width of one CAPTION-size character.
208
227
  *
@@ -214,6 +214,83 @@ var CHART_TOOLTIP_MAX_WIDTH = 320;
214
214
  /** Gap in px between the plot box and a side-placed legend. */
215
215
  var CHART_LEGEND_SIDE_GAP = 16;
216
216
  /**
217
+ * Ghost bar heights, one inner array per group — three bars each, so the
218
+ * skeleton reads as the grouped chart it usually stands in for rather than a
219
+ * sparse row of lone bars.
220
+ */
221
+ var SKELETON_BAR_GROUPS = [
222
+ [
223
+ 65,
224
+ 45,
225
+ 25
226
+ ],
227
+ [
228
+ 80,
229
+ 55,
230
+ 30
231
+ ],
232
+ [
233
+ 45,
234
+ 70,
235
+ 35
236
+ ],
237
+ [
238
+ 70,
239
+ 50,
240
+ 40
241
+ ],
242
+ [
243
+ 55,
244
+ 75,
245
+ 30
246
+ ]
247
+ ];
248
+ /**
249
+ * Ghost lines, one inner array per line, offset from each other and drawn with
250
+ * their area fills so the skeleton has the layered depth of a real multi-series
251
+ * chart instead of a single bare stroke.
252
+ */
253
+ var SKELETON_LINE_SERIES = [
254
+ [
255
+ 30,
256
+ 55,
257
+ 45,
258
+ 70,
259
+ 60,
260
+ 85,
261
+ 75
262
+ ],
263
+ [
264
+ 20,
265
+ 35,
266
+ 50,
267
+ 40,
268
+ 60,
269
+ 55,
270
+ 70
271
+ ],
272
+ [
273
+ 10,
274
+ 25,
275
+ 20,
276
+ 35,
277
+ 30,
278
+ 45,
279
+ 40
280
+ ]
281
+ ];
282
+ /** Ghost donut shares — three arcs, halving. */
283
+ var SKELETON_PIE_VALUES = [
284
+ 5,
285
+ 3,
286
+ 2
287
+ ];
288
+ /**
289
+ * Skeleton pulse period, matching the cadence of `TextShimmer` and
290
+ * `AvatarShimmer` so charts load in step with everything else on the page.
291
+ */
292
+ var CHART_SKELETON_PULSE_MS = 2500;
293
+ /**
217
294
  * Approximate width of one CAPTION-size character.
218
295
  *
219
296
  * Axis sizing estimates label widths arithmetically rather than measuring the
@@ -261,4 +338,4 @@ var CHART_PALETTE_ORDER = [
261
338
  ChartPalette.RED
262
339
  ];
263
340
  //#endregion
264
- 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_LEGEND_SIDE_GAP, CHART_MARK_OPACITY_ACTIVE, 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 };
341
+ 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_LEGEND_SIDE_GAP, CHART_MARK_OPACITY_ACTIVE, CHART_MARK_OPACITY_MUTED, CHART_PALETTE_ORDER, CHART_RESTORE_DELAY_MS, CHART_SKELETON_PULSE_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, SKELETON_BAR_GROUPS, SKELETON_LINE_SERIES, SKELETON_PIE_VALUES, STACK_SEGMENT_GAP, VALUE_AXIS_LABEL_HEIGHT, VALUE_AXIS_TICK_GAP, WIDTH_FOR_MEDIUM_SPACING, WIDTH_FOR_TIGHT_SPACING };
@@ -25,16 +25,6 @@ interface UseChartInteractionOptions {
25
25
  seriesKeys?: string[];
26
26
  /** Suppress all interaction — used while loading and when the tooltip is off. */
27
27
  disabled?: boolean;
28
- /**
29
- * Render every mark muted, whatever the two axes say.
30
- *
31
- * Distinct from {@link disabled}, which suppresses *input*. Loading suppresses
32
- * *emphasis*: there is nothing yet worth drawing attention to. Folded in here
33
- * rather than left to each mark, because the alternative is the same
34
- * `isLoading ? MUTED : getMarkState(…)` ternary hand-copied at every mark —
35
- * which is exactly how one of them came to be missing it.
36
- */
37
- isLoading?: boolean;
38
28
  }
39
29
  interface MarkStateArgs {
40
30
  /** Omit for marks that belong to no particular category, such as a line. */
@@ -65,5 +55,5 @@ export interface ChartInteraction {
65
55
  onSeriesEnter: (seriesKey: string) => void;
66
56
  onSeriesLeave: () => void;
67
57
  }
68
- export declare function useChartInteraction({ categoryCount, seriesKeys, disabled, isLoading, }: UseChartInteractionOptions): ChartInteraction;
58
+ export declare function useChartInteraction({ categoryCount, seriesKeys, disabled, }: UseChartInteractionOptions): ChartInteraction;
69
59
  export {};
@@ -1,7 +1,7 @@
1
1
  import { ChartMarkState } from "./types.js";
2
2
  import { useCallback, useMemo, useState } from "react";
3
3
  //#region src/charts/useChartInteraction.ts
4
- function useChartInteraction({ categoryCount, seriesKeys, disabled = false, isLoading = false }) {
4
+ function useChartInteraction({ categoryCount, seriesKeys, disabled = false }) {
5
5
  const [hoveredIndex, setHoveredIndex] = useState(null);
6
6
  const [hoveredSeriesKey, setHoveredSeriesKey] = useState(null);
7
7
  const safeHovered = hoveredIndex !== null && hoveredIndex < categoryCount ? hoveredIndex : null;
@@ -21,13 +21,8 @@ function useChartInteraction({ categoryCount, seriesKeys, disabled = false, isLo
21
21
  setHoveredSeriesKey(null);
22
22
  }, []);
23
23
  const getMarkState = useCallback(({ categoryIndex, seriesKey }) => {
24
- if (isLoading) return ChartMarkState.MUTED;
25
24
  return categoryIndex !== void 0 && safeHovered !== null && categoryIndex !== safeHovered || seriesKey !== void 0 && safeHoveredSeries !== null && seriesKey !== safeHoveredSeries ? ChartMarkState.MUTED : ChartMarkState.ACTIVE;
26
- }, [
27
- isLoading,
28
- safeHovered,
29
- safeHoveredSeries
30
- ]);
25
+ }, [safeHovered, safeHoveredSeries]);
31
26
  return useMemo(() => ({
32
27
  activeIndex: safeHovered,
33
28
  hoveredSeriesKey: safeHoveredSeries,
@@ -33,5 +33,12 @@ export interface SeriesColorResolver<TKey extends string> {
33
33
  * imply it is.
34
34
  */
35
35
  neutral: string;
36
+ /**
37
+ * Ghost colour for skeleton marks while the chart is loading.
38
+ *
39
+ * The same token the shimmer components use, so the loading vocabulary is
40
+ * one colour everywhere.
41
+ */
42
+ placeholder: string;
36
43
  }
37
44
  export declare function useSeriesColorResolver<TKey extends string>(series: ChartSeriesStyles<TKey>): SeriesColorResolver<TKey>;
@@ -15,7 +15,8 @@ function useSeriesColorResolver(series) {
15
15
  keys,
16
16
  resolve,
17
17
  resolveByIndex,
18
- neutral: theme.color.text.tertiary
18
+ neutral: theme.color.text.tertiary,
19
+ placeholder: theme.color.border.primary
19
20
  }), [
20
21
  keys,
21
22
  resolve,
package/dist/styles.css CHANGED
@@ -32,29 +32,30 @@
32
32
  .ceqlpek{stroke:none;pointer-events:none;opacity:1;-webkit-transition:opacity 100ms ease-in-out 200ms;transition:opacity 100ms ease-in-out 200ms;}.ceqlpek[data-state="muted"]{opacity:0.1;}@media (prefers-reduced-motion: reduce){.ceqlpek{-webkit-transition:none;transition:none;}}
33
33
  .c1fcbddl{pointer-events:none;opacity:1;-webkit-transition:opacity 100ms ease-in-out 200ms;transition:opacity 100ms ease-in-out 200ms;}.c1fcbddl[data-state="muted"]{opacity:0.1;}@media (prefers-reduced-motion: reduce){.c1fcbddl{-webkit-transition:none;transition:none;}}
34
34
  .cpcxr59{opacity:1;-webkit-transition:opacity 100ms ease-in-out 200ms;transition:opacity 100ms ease-in-out 200ms;}.cpcxr59[data-state="muted"]{opacity:0.1;}@media (prefers-reduced-motion: reduce){.cpcxr59{-webkit-transition:none;transition:none;}}
35
- .c1wvzvu4{fill:transparent;outline:none;}
35
+ .c1wvzvu4{pointer-events:none;-webkit-animation:chartSkeletonPulse-c1wvzvu4 2500ms cubic-bezier(0.4, 0, 0.6, 1) infinite;animation:chartSkeletonPulse-c1wvzvu4 2500ms cubic-bezier(0.4, 0, 0.6, 1) infinite;}@-webkit-keyframes chartSkeletonPulse-c1wvzvu4{0%,100%{opacity:0.75;}50%{opacity:0.25;}}@keyframes chartSkeletonPulse-c1wvzvu4{0%,100%{opacity:0.75;}50%{opacity:0.25;}}@media (prefers-reduced-motion: reduce){.c1wvzvu4{-webkit-animation:none;animation:none;opacity:0.5;}}
36
36
  .c17guewt{fill:transparent;outline:none;}
37
- .cblgiyf{stroke:var(--cblgiyf-0);shape-rendering:crispEdges;}
38
- .c1lr03cc{stroke:var(--c1lr03cc-0);pointer-events:none;}
39
- .cizy1s8{overflow:visible;pointer-events:none;}
40
- .c1ukq11d{position:absolute;z-index:10;pointer-events:none;left:var(--c1ukq11d-0);top:var(--c1ukq11d-1);min-width:168px;max-width:320px;padding:10px 12px;border:0.5px solid var(--c1ukq11d-2);border-radius:6px;background-color:var(--c1ukq11d-3);opacity:var(--c1ukq11d-4);-webkit-transition:opacity 100ms ease-in-out,left 100ms ease-out,top 100ms ease-out;transition:opacity 100ms ease-in-out,left 100ms ease-out,top 100ms ease-out;}@media (prefers-reduced-motion: reduce){.c1ukq11d{-webkit-transition:none;transition:none;}}
41
- .cwcko2m{position:absolute;left:var(--cwcko2m-0);top:var(--cwcko2m-1);width:var(--cwcko2m-2);height:var(--cwcko2m-2);-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);pointer-events:none;text-align:center;}
42
- .cqwhvyz{position:absolute;top:38%;left:50%;-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);max-width:60%;padding:12px;border:0.5px solid var(--cqwhvyz-0);border-radius:6px;background-color:var(--cqwhvyz-1);pointer-events:none;text-align:center;}
43
- .c1iaray{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:var(--c1iaray-0);-ms-flex-direction:var(--c1iaray-0);flex-direction:var(--c1iaray-0);-webkit-box-flex-wrap:var(--c1iaray-1);-webkit-flex-wrap:var(--c1iaray-1);-ms-flex-wrap:var(--c1iaray-1);flex-wrap:var(--c1iaray-1);-webkit-align-items:var(--c1iaray-2);-webkit-box-align:var(--c1iaray-2);-ms-flex-align:var(--c1iaray-2);align-items:var(--c1iaray-2);gap:var(--c1iaray-3);min-width:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;padding-top:var(--c1iaray-4);padding-left:var(--c1iaray-5);}.c1iaray[data-active="true"]>*{transition-delay:0ms;}
44
- .cz6jod1{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:6px;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background:none;border:0;padding:0;margin:0;font:inherit;color:inherit;cursor:default;border-radius:2px;opacity:1;-webkit-transition:opacity 100ms ease-in-out 200ms;transition:opacity 100ms ease-in-out 200ms;}.cz6jod1[data-state="muted"]{opacity:0.1;}@media (prefers-reduced-motion: reduce){.cz6jod1{-webkit-transition:none;transition:none;}}.cz6jod1:focus-visible{outline:1.5px solid currentColor;outline-offset:2px;}
45
- .c1de5mqk{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:6px;opacity:1;-webkit-transition:opacity 100ms ease-in-out 200ms;transition:opacity 100ms ease-in-out 200ms;}.c1de5mqk[data-state="muted"]{opacity:0.1;}@media (prefers-reduced-motion: reduce){.c1de5mqk{-webkit-transition:none;transition:none;}}
37
+ .cblgiyf{fill:transparent;outline:none;}
38
+ .c1lr03cc{stroke:var(--c1lr03cc-0);shape-rendering:crispEdges;}
39
+ .cizy1s8{stroke:var(--cizy1s8-0);pointer-events:none;}
40
+ .c1ukq11d{overflow:visible;pointer-events:none;}
41
+ .cwcko2m{position:absolute;z-index:10;pointer-events:none;left:var(--cwcko2m-0);top:var(--cwcko2m-1);min-width:168px;max-width:320px;padding:10px 12px;border:0.5px solid var(--cwcko2m-2);border-radius:6px;background-color:var(--cwcko2m-3);opacity:var(--cwcko2m-4);-webkit-transition:opacity 100ms ease-in-out,left 100ms ease-out,top 100ms ease-out;transition:opacity 100ms ease-in-out,left 100ms ease-out,top 100ms ease-out;}@media (prefers-reduced-motion: reduce){.cwcko2m{-webkit-transition:none;transition:none;}}
42
+ .cqwhvyz{position:absolute;left:var(--cqwhvyz-0);top:var(--cqwhvyz-1);width:var(--cqwhvyz-2);height:var(--cqwhvyz-2);-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);pointer-events:none;text-align:center;}
43
+ .c1iaray{position:absolute;top:38%;left:50%;-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);max-width:60%;padding:12px;border:0.5px solid var(--c1iaray-0);border-radius:6px;background-color:var(--c1iaray-1);pointer-events:none;text-align:center;}
44
+ .cz6jod1{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:var(--cz6jod1-0);-ms-flex-direction:var(--cz6jod1-0);flex-direction:var(--cz6jod1-0);-webkit-box-flex-wrap:var(--cz6jod1-1);-webkit-flex-wrap:var(--cz6jod1-1);-ms-flex-wrap:var(--cz6jod1-1);flex-wrap:var(--cz6jod1-1);-webkit-align-items:var(--cz6jod1-2);-webkit-box-align:var(--cz6jod1-2);-ms-flex-align:var(--cz6jod1-2);align-items:var(--cz6jod1-2);gap:var(--cz6jod1-3);min-width:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;padding-top:var(--cz6jod1-4);padding-left:var(--cz6jod1-5);}.cz6jod1[data-active="true"]>*{transition-delay:0ms;}
45
+ .c1de5mqk{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:6px;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background:none;border:0;padding:0;margin:0;font:inherit;color:inherit;cursor:default;border-radius:2px;opacity:1;-webkit-transition:opacity 100ms ease-in-out 200ms;transition:opacity 100ms ease-in-out 200ms;}.c1de5mqk[data-state="muted"]{opacity:0.1;}@media (prefers-reduced-motion: reduce){.c1de5mqk{-webkit-transition:none;transition:none;}}.c1de5mqk:focus-visible{outline:1.5px solid currentColor;outline-offset:2px;}
46
+ .cjirv6a{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:6px;opacity:1;-webkit-transition:opacity 100ms ease-in-out 200ms;transition:opacity 100ms ease-in-out 200ms;}.cjirv6a[data-state="muted"]{opacity:0.1;}@media (prefers-reduced-motion: reduce){.cjirv6a{-webkit-transition:none;transition:none;}}
46
47
  .cmbdg2q{width:var(--cmbdg2q-0);height:var(--cmbdg2q-0);border-radius:50%;background-color:var(--cmbdg2q-1);}
47
- .s1yc7aow{position:relative;height:var(--s1yc7aow-0);width:100%;background-color:var(--s1yc7aow-1);border:0.5px solid var(--s1yc7aow-2);border-radius:4px;overflow:hidden;}
48
- .p1sc05jm{position:absolute;top:0;left:0;height:100%;width:var(--p1sc05jm-0);background-color:var(--p1sc05jm-1);-webkit-animation:var(--p1sc05jm-2);animation:var(--p1sc05jm-2);-webkit-transition:width 0.075s ease-in-out;transition:width 0.075s ease-in-out;}@-webkit-keyframes pulse-p1sc05jm{0%,100%{opacity:0.9;}50%{opacity:0.6;}}@keyframes pulse-p1sc05jm{0%,100%{opacity:0.9;}50%{opacity:0.6;}}
49
- .slaxlp8{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto;min-width:140px;background-color:var(--slaxlp8-0);padding:12px 16px;border:0.5px solid var(--slaxlp8-1);border-radius:5px;}
50
- .shdcix9{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;gap:4px;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;min-width:16px;cursor:var(--shdcix9-0);-webkit-transition:border-color 0.1s ease-out;transition:border-color 0.1s ease-out;height:var(--shdcix9-1);padding:var(--shdcix9-2);background-color:var(--shdcix9-3);border:0.5px solid var(--shdcix9-4);border-radius:var(--shdcix9-5);}
51
- .szfsuud{margin-left:0.5px;}.szfsuud>span{display:inline-block;-webkit-animation:ellipsisPulse-szfsuud var(--szfsuud-0) infinite ease-in-out both;animation:ellipsisPulse-szfsuud var(--szfsuud-0) infinite ease-in-out both;-webkit-animation-play-state:var(--szfsuud-1);animation-play-state:var(--szfsuud-1);}.szfsuud>span:nth-child(1){-webkit-animation-delay:0s;animation-delay:0s;}.szfsuud>span:nth-child(2){-webkit-animation-delay:0.2s;animation-delay:0.2s;}.szfsuud>span:nth-child(3){-webkit-animation-delay:0.4s;animation-delay:0.4s;}@-webkit-keyframes ellipsisPulse-szfsuud{0%,80%,100%{opacity:0.5;}40%{opacity:1;}}@keyframes ellipsisPulse-szfsuud{0%,80%,100%{opacity:0.5;}40%{opacity:1;}}
52
48
  .s1p67zkf{display:inline-block;background:linear-gradient(
53
49
  90deg,
54
50
  var(--s1p67zkf-0) 0%,
55
51
  var(--s1p67zkf-0) 75%,
56
52
  var(--s1p67zkf-0) 100%
57
53
  );-webkit-background-size:200% 100%;background-size:200% 100%;-webkit-animation:shimmer-s1p67zkf 2.5s infinite,pulse-s1p67zkf 2.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;animation:shimmer-s1p67zkf 2.5s infinite,pulse-s1p67zkf 2.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;height:var(--s1p67zkf-1);width:var(--s1p67zkf-2);border-radius:var(--s1p67zkf-3);}@-webkit-keyframes shimmer-s1p67zkf{0%{-webkit-background-position:-250% 0;background-position:-250% 0;}100%{-webkit-background-position:150% 0;background-position:150% 0;}}@keyframes shimmer-s1p67zkf{0%{-webkit-background-position:-250% 0;background-position:-250% 0;}100%{-webkit-background-position:150% 0;background-position:150% 0;}}@-webkit-keyframes pulse-s1p67zkf{0%,100%{opacity:0.75;}50%{opacity:0.25;}}@keyframes pulse-s1p67zkf{0%,100%{opacity:0.75;}50%{opacity:0.25;}}
54
+ .s1yc7aow{position:relative;height:var(--s1yc7aow-0);width:100%;background-color:var(--s1yc7aow-1);border:0.5px solid var(--s1yc7aow-2);border-radius:4px;overflow:hidden;}
55
+ .p1sc05jm{position:absolute;top:0;left:0;height:100%;width:var(--p1sc05jm-0);background-color:var(--p1sc05jm-1);-webkit-animation:var(--p1sc05jm-2);animation:var(--p1sc05jm-2);-webkit-transition:width 0.075s ease-in-out;transition:width 0.075s ease-in-out;}@-webkit-keyframes pulse-p1sc05jm{0%,100%{opacity:0.9;}50%{opacity:0.6;}}@keyframes pulse-p1sc05jm{0%,100%{opacity:0.9;}50%{opacity:0.6;}}
56
+ .slaxlp8{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto;min-width:140px;background-color:var(--slaxlp8-0);padding:12px 16px;border:0.5px solid var(--slaxlp8-1);border-radius:5px;}
57
+ .shdcix9{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;gap:4px;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;min-width:16px;cursor:var(--shdcix9-0);-webkit-transition:border-color 0.1s ease-out;transition:border-color 0.1s ease-out;height:var(--shdcix9-1);padding:var(--shdcix9-2);background-color:var(--shdcix9-3);border:0.5px solid var(--shdcix9-4);border-radius:var(--shdcix9-5);}
58
+ .szfsuud{margin-left:0.5px;}.szfsuud>span{display:inline-block;-webkit-animation:ellipsisPulse-szfsuud var(--szfsuud-0) infinite ease-in-out both;animation:ellipsisPulse-szfsuud var(--szfsuud-0) infinite ease-in-out both;-webkit-animation-play-state:var(--szfsuud-1);animation-play-state:var(--szfsuud-1);}.szfsuud>span:nth-child(1){-webkit-animation-delay:0s;animation-delay:0s;}.szfsuud>span:nth-child(2){-webkit-animation-delay:0.2s;animation-delay:0.2s;}.szfsuud>span:nth-child(3){-webkit-animation-delay:0.4s;animation-delay:0.4s;}@-webkit-keyframes ellipsisPulse-szfsuud{0%,80%,100%{opacity:0.5;}40%{opacity:1;}}@keyframes ellipsisPulse-szfsuud{0%,80%,100%{opacity:0.5;}40%{opacity:1;}}
58
59
  .s40bxfr{display:-ms-grid;display:grid;box-sizing:border-box;-ms-grid-columns:var(--s40bxfr-0);grid-template-columns:var(--s40bxfr-0);-ms-grid-rows:var(--s40bxfr-1);grid-template-rows:var(--s40bxfr-1);gap:var(--s40bxfr-2);row-gap:var(--s40bxfr-3);-webkit-column-gap:var(--s40bxfr-4);column-gap:var(--s40bxfr-4);-webkit-align-items:var(--s40bxfr-5);-webkit-box-align:var(--s40bxfr-5);-ms-flex-align:var(--s40bxfr-5);align-items:var(--s40bxfr-5);justify-items:var(--s40bxfr-6);-webkit-align-content:var(--s40bxfr-7);-ms-flex-line-pack:var(--s40bxfr-7);align-content:var(--s40bxfr-7);-webkit-box-pack:var(--s40bxfr-8);-ms-flex-pack:var(--s40bxfr-8);-webkit-justify-content:var(--s40bxfr-8);justify-content:var(--s40bxfr-8);width:var(--s40bxfr-9);height:var(--s40bxfr-10);min-width:var(--s40bxfr-11);max-width:var(--s40bxfr-12);min-height:var(--s40bxfr-13);max-height:var(--s40bxfr-14);overflow:var(--s40bxfr-15);padding:var(--s40bxfr-16);margin:var(--s40bxfr-17);}
59
60
  .s2h3guw{margin:var(--s2h3guw-0);margin-top:var(--s2h3guw-1);margin-right:var(--s2h3guw-2);margin-bottom:var(--s2h3guw-3);margin-left:var(--s2h3guw-4);width:var(--s2h3guw-5);height:var(--s2h3guw-6);}
60
61
  .sck44b4{position:var(--sck44b4-0);min-width:var(--sck44b4-1);width:var(--sck44b4-2);height:var(--sck44b4-3);overflow:var(--sck44b4-4);padding:var(--sck44b4-5);overscroll-behavior:auto;top:var(--sck44b4-6);right:var(--sck44b4-7);bottom:var(--sck44b4-8);left:var(--sck44b4-9);}
@@ -131,7 +132,7 @@
131
132
  .m1jgo9vf{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;pointer-events:auto;}
132
133
  .hvnpu6g{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:120px;height:8px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;cursor:ns-resize;z-index:10;border-radius:4px;background-color:var(--hvnpu6g-0);border:0.5px solid var(--hvnpu6g-1);cursor:ns-resize;}.hvnpu6g:hover{border-color:var(--hvnpu6g-2);background-color:var(--hvnpu6g-3);color:var(--hvnpu6g-4);}
133
134
  .v1ha5e5c{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%, -50%);-moz-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:8px;height:100px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;cursor:ew-resize;z-index:30;border-radius:4px;background-color:var(--v1ha5e5c-0);border:0.5px solid var(--v1ha5e5c-1);cursor:ew-resize;}.v1ha5e5c:hover{border-color:var(--v1ha5e5c-2);background-color:var(--v1ha5e5c-3);color:var(--v1ha5e5c-4);}
134
- .scx8lyz{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:var(--scx8lyz-0);border:0.5px solid var(--scx8lyz-1);border-radius:5px;padding:0 3px;height:28px;}
135
+ .scx8lyz{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:var(--scx8lyz-0);border:0.5px solid var(--scx8lyz-1);border-radius:5px;padding:0 2px;height:28px;}
135
136
  .s1law64s{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;padding:3px 8px;background:var(--s1law64s-0);cursor:pointer;border:0.5px solid var(--s1law64s-1);border-radius:4px;}
136
137
  .m16ywplt{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;padding:4px;width:100%;height:100%;border:0.5px solid transparent;border-radius:4px;cursor:pointer;background-color:transparent;}.m16ywplt:hover{background-color:var(--m16ywplt-0);}.m16ywplt:focus-visible{outline:none;border-color:var(--m16ywplt-1);}
137
138
  .a1wb3h41{position:-webkit-sticky;position:sticky;right:0;top:0;z-index:25;-webkit-flex:0 0 48px;-ms-flex:0 0 48px;flex:0 0 48px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;background-color:var(--a1wb3h41-0);border-left:0.5px solid var(--a1wb3h41-1);border-bottom:0.5px solid var(--a1wb3h41-1);}
@@ -5,7 +5,7 @@ import { styled } from "@linaria/react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/switcher/Switcher.tsx
7
7
  var _exp = () => ({ theme }) => theme.color.background.primary;
8
- var _exp2 = () => ({ theme }) => theme.color.border.primary;
8
+ var _exp2 = () => ({ theme }) => theme.color.border.secondary;
9
9
  var StyledSwitcher = withTheme(/*#__PURE__*/ styled("div")({
10
10
  name: "StyledSwitcher",
11
11
  class: "scx8lyz",
@@ -16,7 +16,7 @@ var StyledSwitcher = withTheme(/*#__PURE__*/ styled("div")({
16
16
  }
17
17
  }));
18
18
  var _exp3 = () => ({ theme, $isSelected }) => $isSelected ? theme.color.background.secondary : "transparent";
19
- var _exp4 = () => ({ theme, $isSelected }) => $isSelected ? theme.color.border.primary : "transparent";
19
+ var _exp4 = () => ({ theme, $isSelected }) => $isSelected ? theme.color.border.tertiary : "transparent";
20
20
  var SwitcherItem = withTheme(/*#__PURE__*/ styled("div")({
21
21
  name: "SwitcherItem",
22
22
  class: "s1law64s",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@galaxy-io/dls",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
4
4
  "description": "Galaxy Design Language System",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",