@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.
- package/dist/charts/BarChart.js +41 -18
- package/dist/charts/ChartAxis.d.ts +11 -2
- package/dist/charts/ChartAxis.js +5 -4
- package/dist/charts/ChartFrame.js +3 -1
- package/dist/charts/ChartLegend.d.ts +9 -1
- package/dist/charts/ChartLegend.js +27 -1
- package/dist/charts/ChartPrimitives.d.ts +13 -0
- package/dist/charts/ChartPrimitives.js +65 -48
- package/dist/charts/ChartTooltip.js +9 -4
- package/dist/charts/LineChart.js +67 -46
- package/dist/charts/PieChart.js +33 -19
- package/dist/charts/constants.d.ts +19 -0
- package/dist/charts/constants.js +78 -1
- package/dist/charts/useChartInteraction.d.ts +1 -11
- package/dist/charts/useChartInteraction.js +2 -7
- package/dist/charts/useSeriesColorResolver.d.ts +7 -0
- package/dist/charts/useSeriesColorResolver.js +2 -1
- package/dist/styles.css +17 -16
- package/dist/switcher/Switcher.js +2 -2
- package/package.json +1 -1
package/dist/charts/BarChart.js
CHANGED
|
@@ -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(
|
|
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(() =>
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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:
|
|
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 {};
|
package/dist/charts/ChartAxis.js
CHANGED
|
@@ -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
|
|
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: "
|
|
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: "
|
|
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
|
|
191
|
+
var _exp16 = () => ({ theme }) => theme.color.border.primary;
|
|
175
192
|
var ChartGridLine = withTheme(/*#__PURE__*/ styled("line")({
|
|
176
193
|
name: "ChartGridLine",
|
|
177
|
-
class: "
|
|
194
|
+
class: "c1lr03cc",
|
|
178
195
|
propsAsIs: true,
|
|
179
|
-
vars: { "
|
|
196
|
+
vars: { "c1lr03cc-0": [_exp16()] }
|
|
180
197
|
}));
|
|
181
198
|
/** Vertical rule marking the hovered category on a line chart. */
|
|
182
|
-
var
|
|
199
|
+
var _exp17 = () => ({ theme }) => theme.color.border.secondary;
|
|
183
200
|
var ChartCursorLine = withTheme(/*#__PURE__*/ styled("line")({
|
|
184
201
|
name: "ChartCursorLine",
|
|
185
|
-
class: "
|
|
202
|
+
class: "cizy1s8",
|
|
186
203
|
propsAsIs: true,
|
|
187
|
-
vars: { "
|
|
204
|
+
vars: { "cizy1s8-0": [_exp17()] }
|
|
188
205
|
}));
|
|
189
206
|
var ChartAxisLabelBox = /*#__PURE__*/ styled("foreignObject")({
|
|
190
207
|
name: "ChartAxisLabelBox",
|
|
191
|
-
class: "
|
|
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
|
|
202
|
-
var
|
|
203
|
-
var
|
|
204
|
-
var
|
|
205
|
-
var
|
|
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: "
|
|
225
|
+
class: "cwcko2m",
|
|
209
226
|
propsAsIs: false,
|
|
210
227
|
vars: {
|
|
211
|
-
"
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
"
|
|
215
|
-
"
|
|
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
|
|
227
|
-
var
|
|
228
|
-
var
|
|
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: "
|
|
248
|
+
class: "cqwhvyz",
|
|
232
249
|
propsAsIs: false,
|
|
233
250
|
vars: {
|
|
234
|
-
"
|
|
235
|
-
"
|
|
236
|
-
"
|
|
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
|
|
244
|
-
var
|
|
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: "
|
|
264
|
+
class: "c1iaray",
|
|
248
265
|
propsAsIs: false,
|
|
249
266
|
vars: {
|
|
250
|
-
"
|
|
251
|
-
"
|
|
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
|
|
264
|
-
var
|
|
265
|
-
var
|
|
266
|
-
var
|
|
267
|
-
var
|
|
268
|
-
var
|
|
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: "
|
|
288
|
+
class: "cz6jod1",
|
|
272
289
|
propsAsIs: false,
|
|
273
290
|
vars: {
|
|
274
|
-
"
|
|
275
|
-
"
|
|
276
|
-
"
|
|
277
|
-
"
|
|
278
|
-
"
|
|
279
|
-
"
|
|
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: "
|
|
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: "
|
|
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(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
})]
|
package/dist/charts/LineChart.js
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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 ||
|
|
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
|
-
|
|
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
|
package/dist/charts/PieChart.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
*
|
package/dist/charts/constants.js
CHANGED
|
@@ -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,
|
|
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
|
|
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>;
|
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{
|
|
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{
|
|
38
|
-
.c1lr03cc{stroke:var(--c1lr03cc-0);
|
|
39
|
-
.cizy1s8{
|
|
40
|
-
.c1ukq11d{
|
|
41
|
-
.cwcko2m{position:absolute;left:var(--cwcko2m-0);top:var(--cwcko2m-1);width:var(--cwcko2m-2);
|
|
42
|
-
.cqwhvyz{position:absolute;top:
|
|
43
|
-
.c1iaray{
|
|
44
|
-
.cz6jod1{display:-webkit-
|
|
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
|
|
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.
|
|
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.
|
|
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",
|