@pharos-ds/charts 0.0.0-bootstrap.0 → 1.0.10-canary.2189f39
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/CHANGELOG.md +73 -0
- package/LICENSE +24 -0
- package/README.md +118 -0
- package/dist/Chart.d.ts +62 -0
- package/dist/Chart.d.ts.map +1 -0
- package/dist/Chart.js +401 -0
- package/dist/ChartAxis.d.ts +37 -0
- package/dist/ChartAxis.d.ts.map +1 -0
- package/dist/ChartAxis.js +233 -0
- package/dist/ChartContext.d.ts +4 -0
- package/dist/ChartContext.d.ts.map +1 -0
- package/dist/ChartContext.js +15 -0
- package/dist/ChartGrid.d.ts +26 -0
- package/dist/ChartGrid.d.ts.map +1 -0
- package/dist/ChartGrid.js +118 -0
- package/dist/ChartLegend.d.ts +14 -0
- package/dist/ChartLegend.d.ts.map +1 -0
- package/dist/ChartLegend.js +62 -0
- package/dist/ChartSwatch.d.ts +36 -0
- package/dist/ChartSwatch.d.ts.map +1 -0
- package/dist/ChartSwatch.js +85 -0
- package/dist/ChartTooltip.d.ts +46 -0
- package/dist/ChartTooltip.d.ts.map +1 -0
- package/dist/ChartTooltip.js +330 -0
- package/dist/charts.css +33 -0
- package/dist/dataTable.d.ts +56 -0
- package/dist/dataTable.d.ts.map +1 -0
- package/dist/dataTable.js +88 -0
- package/dist/formatters.d.ts +37 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +156 -0
- package/dist/getChartColors.d.ts +67 -0
- package/dist/getChartColors.d.ts.map +1 -0
- package/dist/getChartColors.js +191 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/layout.d.ts +40 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +322 -0
- package/dist/legend.d.ts +17 -0
- package/dist/legend.d.ts.map +1 -0
- package/dist/legend.js +40 -0
- package/dist/markColor.d.ts +20 -0
- package/dist/markColor.d.ts.map +1 -0
- package/dist/markColor.js +56 -0
- package/dist/marks/area.d.ts +19 -0
- package/dist/marks/area.d.ts.map +1 -0
- package/dist/marks/area.js +121 -0
- package/dist/marks/band.d.ts +9 -0
- package/dist/marks/band.d.ts.map +1 -0
- package/dist/marks/band.js +64 -0
- package/dist/marks/bar.d.ts +21 -0
- package/dist/marks/bar.d.ts.map +1 -0
- package/dist/marks/bar.js +161 -0
- package/dist/marks/candlestick.d.ts +16 -0
- package/dist/marks/candlestick.d.ts.map +1 -0
- package/dist/marks/candlestick.js +110 -0
- package/dist/marks/dot.d.ts +19 -0
- package/dist/marks/dot.d.ts.map +1 -0
- package/dist/marks/dot.js +98 -0
- package/dist/marks/dotGL.d.ts +16 -0
- package/dist/marks/dotGL.d.ts.map +1 -0
- package/dist/marks/dotGL.js +231 -0
- package/dist/marks/dotGLInteractive.d.ts +35 -0
- package/dist/marks/dotGLInteractive.d.ts.map +1 -0
- package/dist/marks/dotGLInteractive.js +584 -0
- package/dist/marks/errorBar.d.ts +29 -0
- package/dist/marks/errorBar.d.ts.map +1 -0
- package/dist/marks/errorBar.js +95 -0
- package/dist/marks/heatmapGL.d.ts +27 -0
- package/dist/marks/heatmapGL.d.ts.map +1 -0
- package/dist/marks/heatmapGL.js +335 -0
- package/dist/marks/index.d.ts +13 -0
- package/dist/marks/index.d.ts.map +1 -0
- package/dist/marks/index.js +14 -0
- package/dist/marks/line.d.ts +18 -0
- package/dist/marks/line.d.ts.map +1 -0
- package/dist/marks/line.js +83 -0
- package/dist/marks/referenceLine.d.ts +37 -0
- package/dist/marks/referenceLine.d.ts.map +1 -0
- package/dist/marks/referenceLine.js +204 -0
- package/dist/marks/streamGL.d.ts +41 -0
- package/dist/marks/streamGL.d.ts.map +1 -0
- package/dist/marks/streamGL.js +317 -0
- package/dist/tooltip.d.ts +38 -0
- package/dist/tooltip.d.ts.map +1 -0
- package/dist/tooltip.js +57 -0
- package/dist/types.d.ts +193 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +70 -0
- package/dist/useChartColors.d.ts +16 -0
- package/dist/useChartColors.d.ts.map +1 -0
- package/dist/useChartColors.js +37 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +31 -0
- package/dist/webgl.d.ts +77 -0
- package/dist/webgl.d.ts.map +1 -0
- package/dist/webgl.js +235 -0
- package/package.json +72 -4
- package/src/Chart.doc.mjs +174 -0
- package/src/Chart.test.tsx +273 -0
- package/src/Chart.tsx +535 -0
- package/src/ChartAxis.tsx +289 -0
- package/src/ChartContext.ts +18 -0
- package/src/ChartGrid.tsx +136 -0
- package/src/ChartLegend.tsx +77 -0
- package/src/ChartSwatch.doc.mjs +17 -0
- package/src/ChartSwatch.tsx +89 -0
- package/src/ChartTooltip.tsx +452 -0
- package/src/charts.css.d.ts +3 -0
- package/src/dataTable.test.ts +86 -0
- package/src/dataTable.ts +124 -0
- package/src/formatters.ts +167 -0
- package/src/getChartColors.test.ts +114 -0
- package/src/getChartColors.ts +282 -0
- package/src/index.ts +88 -0
- package/src/layout.ts +372 -0
- package/src/legend.ts +44 -0
- package/src/markColor.ts +70 -0
- package/src/marks/area.tsx +142 -0
- package/src/marks/band.tsx +86 -0
- package/src/marks/bar.tsx +210 -0
- package/src/marks/candlestick.tsx +128 -0
- package/src/marks/dot.tsx +119 -0
- package/src/marks/dotGL.tsx +274 -0
- package/src/marks/dotGLInteractive.tsx +660 -0
- package/src/marks/errorBar.tsx +119 -0
- package/src/marks/heatmapGL.tsx +392 -0
- package/src/marks/index.ts +17 -0
- package/src/marks/line.tsx +118 -0
- package/src/marks/referenceLine.tsx +252 -0
- package/src/marks/streamGL.tsx +381 -0
- package/src/tooltip.ts +73 -0
- package/src/types.ts +212 -0
- package/src/useChartColors.ts +41 -0
- package/src/utils.ts +38 -0
- package/src/webgl.ts +262 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ChartAxisProps {
|
|
2
|
+
/** Which edge to render the axis on */
|
|
3
|
+
position: 'top' | 'right' | 'bottom' | 'left';
|
|
4
|
+
/** Number of ticks (approximate — d3 decides final count) */
|
|
5
|
+
tickCount?: number;
|
|
6
|
+
/** Maximum number of tick labels to show. Labels are evenly skipped when exceeded. */
|
|
7
|
+
maxTicks?: number;
|
|
8
|
+
/** Custom tick formatter */
|
|
9
|
+
tickFormat?: (value: unknown) => string;
|
|
10
|
+
/** Truncate labels to this many characters (appends "\u2026"). */
|
|
11
|
+
truncate?: number;
|
|
12
|
+
/** Enable smooth transitions for streaming (default: true) */
|
|
13
|
+
animated?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Show the axis edge line. Defaults to `true` for the category axis
|
|
16
|
+
* (`position="bottom"`, or `position="left"` in a horizontal chart), `false`
|
|
17
|
+
* otherwise. Forced to `true` when `showTicks` is enabled.
|
|
18
|
+
* Pair with `<ChartGrid vertical />` and pass `showAxisLine` on the
|
|
19
|
+
* corresponding side axis to keep the visual edge grounded.
|
|
20
|
+
*/
|
|
21
|
+
showAxisLine?: boolean;
|
|
22
|
+
/** Show perpendicular tick marks at each tick label. Default: `false`. */
|
|
23
|
+
showTicks?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Chart axis. Always draws tick labels; the axis edge line and tick marks
|
|
27
|
+
* are independently toggleable. Pair with `<ChartGrid>` for grid lines.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```
|
|
31
|
+
* <ChartAxis position="bottom" /> // edge line + labels
|
|
32
|
+
* <ChartAxis position="left" /> // labels only (no edge line)
|
|
33
|
+
* <ChartAxis position="left" showAxisLine showTicks />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function ChartAxis({ position, tickCount, maxTicks, tickFormat, truncate, animated, showAxisLine, showTicks, }: ChartAxisProps): import("react").JSX.Element;
|
|
37
|
+
//# sourceMappingURL=ChartAxis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartAxis.d.ts","sourceRoot":"","sources":["../src/ChartAxis.tsx"],"names":[],"mappings":"AA+BA,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC9C,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;IACxC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,SAAa,EACb,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,QAAe,EACf,YAAY,EACZ,SAAiB,GAClB,EAAE,cAAc,+BAuMhB"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ChartAxis.tsx (v2)
|
|
5
|
+
* @output Renders an axis (top, right, bottom, left) using the chart's scales
|
|
6
|
+
* @position Child of Chart v2; reads scales from chart context
|
|
7
|
+
*
|
|
8
|
+
* The axis edge line and tick marks are independently toggleable so callers
|
|
9
|
+
* can compose: line-only, line + ticks, or line + ticks + grid (paired with
|
|
10
|
+
* `<ChartGrid>`). To stay consistent with most charts, the bottom axis
|
|
11
|
+
* draws its edge line by default and other positions don't.
|
|
12
|
+
*
|
|
13
|
+
* Labels use d3's native tick formatter for continuous scales by default (clean
|
|
14
|
+
* numbers/dates) unless a `tickFormat` is supplied, and are auto-thinned to the
|
|
15
|
+
* available width (horizontal) or height (vertical) to avoid overlap.
|
|
16
|
+
*
|
|
17
|
+
* Ticks use CSS transitions for smooth sliding during streaming updates.
|
|
18
|
+
*
|
|
19
|
+
* Orientation-aware: in a horizontal chart the context hands over display-space
|
|
20
|
+
* scales (values on x, categories on y), so `position="bottom"` shows values and
|
|
21
|
+
* `position="left"` shows categories. The default edge line follows the value
|
|
22
|
+
* baseline: bottom for vertical charts, left for horizontal ones.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { useCallback, useMemo } from 'react';
|
|
26
|
+
import * as stylex from '@stylexjs/stylex';
|
|
27
|
+
import '@pharos-ds/core/theme/tokens.stylex';
|
|
28
|
+
import { colorVars } from '@pharos-ds/core/theme/tokens.stylex';
|
|
29
|
+
import { useChart } from "./ChartContext.js";
|
|
30
|
+
import { isBandScale } from "./utils.js";
|
|
31
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
32
|
+
const TICK_SIZE = 6;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Chart axis. Always draws tick labels; the axis edge line and tick marks
|
|
36
|
+
* are independently toggleable. Pair with `<ChartGrid>` for grid lines.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```
|
|
40
|
+
* <ChartAxis position="bottom" /> // edge line + labels
|
|
41
|
+
* <ChartAxis position="left" /> // labels only (no edge line)
|
|
42
|
+
* <ChartAxis position="left" showAxisLine showTicks />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function ChartAxis({
|
|
46
|
+
position,
|
|
47
|
+
tickCount = 5,
|
|
48
|
+
maxTicks,
|
|
49
|
+
tickFormat,
|
|
50
|
+
truncate,
|
|
51
|
+
animated = true,
|
|
52
|
+
showAxisLine,
|
|
53
|
+
showTicks = false
|
|
54
|
+
}) {
|
|
55
|
+
const {
|
|
56
|
+
width,
|
|
57
|
+
height,
|
|
58
|
+
xScale,
|
|
59
|
+
yScale,
|
|
60
|
+
yBandScale,
|
|
61
|
+
orientation
|
|
62
|
+
} = useChart();
|
|
63
|
+
const isHorizontalChart = orientation === 'horizontal';
|
|
64
|
+
// Tick marks need an axis line to anchor against; force it on when ticks
|
|
65
|
+
// are enabled so the two visuals stay coherent.
|
|
66
|
+
const renderAxisLine = (showAxisLine ?? position === (isHorizontalChart ? 'left' : 'bottom')) || showTicks;
|
|
67
|
+
const isHorizontal = position === 'top' || position === 'bottom';
|
|
68
|
+
// A categorical y-axis (e.g. heatmap rows) is exposed as `yBandScale`; prefer
|
|
69
|
+
// it over the linear `yScale` so a left/right axis renders the row categories
|
|
70
|
+
// (days) aligned to each band instead of meaningless value ticks.
|
|
71
|
+
const scale = isHorizontal ? xScale : yBandScale ?? yScale;
|
|
72
|
+
|
|
73
|
+
// Sanitize the tick count before it reaches d3. `.ticks()` targets ~N ticks
|
|
74
|
+
// and allocates an array that large, so a huge N throws `RangeError: Invalid
|
|
75
|
+
// array length` and crashes the render; a non-finite or negative N would
|
|
76
|
+
// otherwise blank the axis. Clamp to a sane integer (0 still means "no
|
|
77
|
+
// ticks") and fall back to the default for invalid input. Shared by tick
|
|
78
|
+
// generation and the auto formatter so the two stay in sync.
|
|
79
|
+
const safeTickCount = Number.isFinite(tickCount) && tickCount >= 0 ? Math.min(Math.floor(tickCount), 1000) : 5;
|
|
80
|
+
|
|
81
|
+
// Default label formatter. For continuous (linear/time) scales, use d3's own
|
|
82
|
+
// tick formatter so numbers get sensible precision (no floating-point dust
|
|
83
|
+
// like "0.30000000000000004") and dates render as calendar labels instead of
|
|
84
|
+
// `String(Date)`. Band scales keep their category strings.
|
|
85
|
+
const autoFormat = useMemo(() => {
|
|
86
|
+
if (tickFormat || isBandScale(scale)) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const continuous = scale;
|
|
90
|
+
const fmt = continuous.tickFormat(safeTickCount);
|
|
91
|
+
return v => fmt(v);
|
|
92
|
+
}, [tickFormat, scale, safeTickCount]);
|
|
93
|
+
const format = useCallback(value => {
|
|
94
|
+
const str = (tickFormat ?? autoFormat ?? String)(value);
|
|
95
|
+
return truncate && str.length > truncate ? str.slice(0, truncate) + '\u2026' : str;
|
|
96
|
+
}, [tickFormat, autoFormat, truncate]);
|
|
97
|
+
const ticks = useMemo(() => {
|
|
98
|
+
let allTicks;
|
|
99
|
+
if (isBandScale(scale)) {
|
|
100
|
+
allTicks = scale.domain().map(d => ({
|
|
101
|
+
value: d,
|
|
102
|
+
offset: (scale(d) ?? 0) + scale.bandwidth() / 2
|
|
103
|
+
}));
|
|
104
|
+
} else {
|
|
105
|
+
const linearScale = scale;
|
|
106
|
+
allTicks = linearScale.ticks(safeTickCount).map(d => ({
|
|
107
|
+
value: d,
|
|
108
|
+
offset: linearScale(d)
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Cap label count to avoid overlap. An explicit `maxTicks` always wins.
|
|
113
|
+
// Otherwise derive a cap from the available space and label size so dense
|
|
114
|
+
// axes don't smear into an unreadable blur: width ÷ widest-label for
|
|
115
|
+
// horizontal (e.g. 30 daily categories), height ÷ line-height for vertical
|
|
116
|
+
// (e.g. a categorical y-axis on a horizontal bar chart). Labels are then
|
|
117
|
+
// evenly skipped down to the cap.
|
|
118
|
+
let cap = maxTicks;
|
|
119
|
+
if (cap == null && allTicks.length > 1) {
|
|
120
|
+
if (isHorizontal && width > 0) {
|
|
121
|
+
const widestChars = allTicks.reduce((m, t) => Math.max(m, format(t.value).length), 1);
|
|
122
|
+
const approxLabelPx = widestChars * 7 + 16;
|
|
123
|
+
cap = Math.max(1, Math.floor(width / approxLabelPx));
|
|
124
|
+
} else if (!isHorizontal && height > 0) {
|
|
125
|
+
// ~12px glyph + breathing room keeps stacked labels from touching.
|
|
126
|
+
cap = Math.max(1, Math.floor(height / 18));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (cap && allTicks.length > cap) {
|
|
130
|
+
const step = Math.ceil(allTicks.length / cap);
|
|
131
|
+
allTicks = allTicks.filter((_, i) => i % step === 0);
|
|
132
|
+
}
|
|
133
|
+
return allTicks;
|
|
134
|
+
}, [scale, safeTickCount, maxTicks, isHorizontal, width, height, format]);
|
|
135
|
+
const transform = position === 'bottom' ? `translate(0,${height})` : position === 'right' ? `translate(${width},0)` : undefined;
|
|
136
|
+
|
|
137
|
+
// For the bottom axis, draw the axis line at y=0 when the domain spans
|
|
138
|
+
// negative values (so the axis line still represents zero, not the chart edge).
|
|
139
|
+
const axisLineY = (() => {
|
|
140
|
+
// Categorical y (e.g. heatmap rows): there is no meaningful zero, and the
|
|
141
|
+
// linear yScale is degenerate — anchor the bottom edge line to the plot edge
|
|
142
|
+
// so it frames the grid instead of cutting across the cells.
|
|
143
|
+
if (position !== 'bottom' || yBandScale || isHorizontalChart) {
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
const domain = yScale.domain();
|
|
147
|
+
if (domain[0] < 0 && domain[1] > 0) {
|
|
148
|
+
return yScale(0) - height;
|
|
149
|
+
}
|
|
150
|
+
return 0;
|
|
151
|
+
})();
|
|
152
|
+
|
|
153
|
+
// Horizontal charts: the left edge line marks value zero when the value
|
|
154
|
+
// domain spans negative values (mirror of `axisLineY` above).
|
|
155
|
+
const axisLineX = (() => {
|
|
156
|
+
if (position !== 'left' || !isHorizontalChart || isBandScale(xScale)) {
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
const domain = xScale.domain();
|
|
160
|
+
if (domain[0] < 0 && domain[1] > 0) {
|
|
161
|
+
return xScale(0);
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
})();
|
|
165
|
+
const tickTransition = animated ? 'transform 150ms linear, opacity 150ms ease' : undefined;
|
|
166
|
+
return /*#__PURE__*/_jsxs("g", {
|
|
167
|
+
transform: transform,
|
|
168
|
+
role: "group",
|
|
169
|
+
"aria-label": `${position} axis`,
|
|
170
|
+
children: [renderAxisLine && /*#__PURE__*/_jsx("line", {
|
|
171
|
+
x1: isHorizontal ? 0 : axisLineX,
|
|
172
|
+
x2: isHorizontal ? width : axisLineX,
|
|
173
|
+
y1: isHorizontal ? axisLineY : 0,
|
|
174
|
+
y2: isHorizontal ? axisLineY : height,
|
|
175
|
+
...{
|
|
176
|
+
className: "x1lo1t26 xnpr05h"
|
|
177
|
+
}
|
|
178
|
+
}), ticks.map(({
|
|
179
|
+
value,
|
|
180
|
+
offset
|
|
181
|
+
}) => {
|
|
182
|
+
const label = format(value);
|
|
183
|
+
// Key off the raw tick value, not the formatted label: distinct ticks
|
|
184
|
+
// can format (or truncate) to the same string and would collide as keys.
|
|
185
|
+
const key = String(value);
|
|
186
|
+
const isVisible = isHorizontal ? offset >= -10 && offset <= width + 10 : offset >= -10 && offset <= height + 10;
|
|
187
|
+
if (isHorizontal) {
|
|
188
|
+
const y = position === 'bottom' ? TICK_SIZE : -TICK_SIZE;
|
|
189
|
+
return /*#__PURE__*/_jsxs("g", {
|
|
190
|
+
style: {
|
|
191
|
+
transform: `translateX(${offset}px)`,
|
|
192
|
+
transition: tickTransition,
|
|
193
|
+
opacity: isVisible ? 1 : 0
|
|
194
|
+
},
|
|
195
|
+
children: [showTicks && /*#__PURE__*/_jsx("line", {
|
|
196
|
+
y2: y,
|
|
197
|
+
...{
|
|
198
|
+
className: "x1lo1t26 xnpr05h"
|
|
199
|
+
}
|
|
200
|
+
}), /*#__PURE__*/_jsx("text", {
|
|
201
|
+
y: position === 'bottom' ? TICK_SIZE + 12 : -(TICK_SIZE + 4),
|
|
202
|
+
textAnchor: "middle",
|
|
203
|
+
fill: "var(--color-text-secondary)",
|
|
204
|
+
fontSize: 12,
|
|
205
|
+
children: label
|
|
206
|
+
})]
|
|
207
|
+
}, key);
|
|
208
|
+
}
|
|
209
|
+
// Vertical axis
|
|
210
|
+
const x = position === 'left' ? -TICK_SIZE : TICK_SIZE;
|
|
211
|
+
return /*#__PURE__*/_jsxs("g", {
|
|
212
|
+
style: {
|
|
213
|
+
transform: `translateY(${offset}px)`,
|
|
214
|
+
transition: tickTransition,
|
|
215
|
+
opacity: isVisible ? 1 : 0
|
|
216
|
+
},
|
|
217
|
+
children: [showTicks && /*#__PURE__*/_jsx("line", {
|
|
218
|
+
x2: x,
|
|
219
|
+
...{
|
|
220
|
+
className: "x1lo1t26 xnpr05h"
|
|
221
|
+
}
|
|
222
|
+
}), /*#__PURE__*/_jsx("text", {
|
|
223
|
+
x: position === 'left' ? -(TICK_SIZE + 4) : TICK_SIZE + 4,
|
|
224
|
+
dy: "0.32em",
|
|
225
|
+
textAnchor: position === 'left' ? 'end' : 'start',
|
|
226
|
+
fill: "var(--color-text-secondary)",
|
|
227
|
+
fontSize: 12,
|
|
228
|
+
children: label
|
|
229
|
+
})]
|
|
230
|
+
}, key);
|
|
231
|
+
})]
|
|
232
|
+
});
|
|
233
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartContext.d.ts","sourceRoot":"","sources":["../src/ChartContext.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,SAAS,CAAC;AAI1C,eAAO,MAAM,aAAa,+CAAe,CAAC;AAE1C,wBAAgB,QAAQ,IAAI,YAAY,CAMvC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import { createContext, useContext } from 'react';
|
|
6
|
+
const Ctx = /*#__PURE__*/createContext(null);
|
|
7
|
+
Ctx.displayName = 'ChartContext';
|
|
8
|
+
export const ChartProvider = Ctx.Provider;
|
|
9
|
+
export function useChart() {
|
|
10
|
+
const ctx = useContext(Ctx);
|
|
11
|
+
if (!ctx) {
|
|
12
|
+
throw new Error('Must be used inside <Chart>');
|
|
13
|
+
}
|
|
14
|
+
return ctx;
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface ChartGridProps {
|
|
2
|
+
/** Show horizontal grid lines. Default: `true` (`false` in horizontal charts). */
|
|
3
|
+
horizontal?: boolean;
|
|
4
|
+
/** Show vertical grid lines. Default: `false` (`true` in horizontal charts). */
|
|
5
|
+
vertical?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Approximate number of grid lines per axis. Match your `<ChartAxis>`
|
|
8
|
+
* `tickCount` so grid lines and tick labels land on the same values.
|
|
9
|
+
* Default: `5`.
|
|
10
|
+
*/
|
|
11
|
+
tickCount?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Grid lines behind chart marks.
|
|
15
|
+
*
|
|
16
|
+
* Pair with `<ChartAxis>` so users always see an axis line beside the
|
|
17
|
+
* grid — the components are designed to be used together.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```
|
|
21
|
+
* <ChartGrid /> // horizontal grid lines (default)
|
|
22
|
+
* <ChartGrid horizontal vertical />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function ChartGrid({ horizontal: horizontalProp, vertical: verticalProp, tickCount, }: ChartGridProps): import("react").JSX.Element;
|
|
26
|
+
//# sourceMappingURL=ChartGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartGrid.d.ts","sourceRoot":"","sources":["../src/ChartGrid.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AASD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,EACxB,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,YAAY,EACtB,SAAa,GACd,EAAE,cAAc,+BAgFhB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ChartGrid.tsx (v2)
|
|
5
|
+
* @output Grid lines behind chart marks
|
|
6
|
+
* @position Child of Chart v2; reads scales from chart context
|
|
7
|
+
*
|
|
8
|
+
* Defaults follow the value axis: horizontal lines for vertical charts,
|
|
9
|
+
* vertical lines for `orientation="horizontal"` charts. In a horizontal chart
|
|
10
|
+
* with categorical rows, explicit `horizontal` lines sit on the row centers.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useMemo } from 'react';
|
|
14
|
+
import * as stylex from '@stylexjs/stylex';
|
|
15
|
+
import '@pharos-ds/core/theme/tokens.stylex';
|
|
16
|
+
import { colorVars } from '@pharos-ds/core/theme/tokens.stylex';
|
|
17
|
+
import { useChart } from "./ChartContext.js";
|
|
18
|
+
import { isBandScale } from "./utils.js";
|
|
19
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
20
|
+
/**
|
|
21
|
+
* Grid lines behind chart marks.
|
|
22
|
+
*
|
|
23
|
+
* Pair with `<ChartAxis>` so users always see an axis line beside the
|
|
24
|
+
* grid — the components are designed to be used together.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```
|
|
28
|
+
* <ChartGrid /> // horizontal grid lines (default)
|
|
29
|
+
* <ChartGrid horizontal vertical />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function ChartGrid({
|
|
33
|
+
horizontal: horizontalProp,
|
|
34
|
+
vertical: verticalProp,
|
|
35
|
+
tickCount = 5
|
|
36
|
+
}) {
|
|
37
|
+
const {
|
|
38
|
+
width,
|
|
39
|
+
height,
|
|
40
|
+
xScale,
|
|
41
|
+
yScale,
|
|
42
|
+
yBandScale,
|
|
43
|
+
orientation
|
|
44
|
+
} = useChart();
|
|
45
|
+
const isHorizontalChart = orientation === 'horizontal';
|
|
46
|
+
const horizontal = horizontalProp ?? !isHorizontalChart;
|
|
47
|
+
const vertical = verticalProp ?? isHorizontalChart;
|
|
48
|
+
|
|
49
|
+
// Sanitize the tick count before it reaches d3's `.ticks()`: it targets ~N
|
|
50
|
+
// ticks and allocates an array that large, so a huge N throws `RangeError:
|
|
51
|
+
// Invalid array length` and crashes the render, while a non-finite or
|
|
52
|
+
// negative N would misbehave. Clamp to a sane integer (0 still means "no
|
|
53
|
+
// lines") and fall back to the default for invalid input.
|
|
54
|
+
const safeTickCount = Number.isFinite(tickCount) && tickCount >= 0 ? Math.min(Math.floor(tickCount), 1000) : 5;
|
|
55
|
+
|
|
56
|
+
// Skip the y=0 line when emphasizing it via the axis. Without this we'd
|
|
57
|
+
// double-draw on top of the axis line. Each line carries its tick `value`,
|
|
58
|
+
// used as a stable React key — the pixel position can be NaN/duplicated for
|
|
59
|
+
// degenerate (zero-range / unmeasured) scales and would collide as a key.
|
|
60
|
+
const hLines = useMemo(() => {
|
|
61
|
+
if (!horizontal) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
if (isHorizontalChart && yBandScale) {
|
|
65
|
+
return yBandScale.domain().map(d => ({
|
|
66
|
+
value: d,
|
|
67
|
+
pos: (yBandScale(d) ?? 0) + yBandScale.bandwidth() / 2
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
return yScale.ticks(safeTickCount).filter(tick => tick !== 0).map(tick => ({
|
|
71
|
+
value: tick,
|
|
72
|
+
pos: yScale(tick)
|
|
73
|
+
}));
|
|
74
|
+
}, [horizontal, yScale, yBandScale, isHorizontalChart, safeTickCount]);
|
|
75
|
+
const vLines = useMemo(() => {
|
|
76
|
+
if (!vertical) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
if (isBandScale(xScale)) {
|
|
80
|
+
return xScale.domain().map(d => ({
|
|
81
|
+
value: d,
|
|
82
|
+
pos: (xScale(d) ?? 0) + xScale.bandwidth() / 2
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
const linear = xScale;
|
|
86
|
+
return linear.ticks(safeTickCount)
|
|
87
|
+
// Horizontal charts draw value zero with the left axis line.
|
|
88
|
+
.filter(d => !(isHorizontalChart && Number(d) === 0)).map(d => ({
|
|
89
|
+
value: String(d),
|
|
90
|
+
pos: linear(d)
|
|
91
|
+
}));
|
|
92
|
+
}, [vertical, xScale, safeTickCount, isHorizontalChart]);
|
|
93
|
+
return /*#__PURE__*/_jsxs("g", {
|
|
94
|
+
children: [hLines.map(({
|
|
95
|
+
value,
|
|
96
|
+
pos
|
|
97
|
+
}) => /*#__PURE__*/_jsx("line", {
|
|
98
|
+
x1: 0,
|
|
99
|
+
x2: width,
|
|
100
|
+
y1: pos,
|
|
101
|
+
y2: pos,
|
|
102
|
+
...{
|
|
103
|
+
className: "x113i6qz xnpr05h"
|
|
104
|
+
}
|
|
105
|
+
}, `h-${value}`)), vLines.map(({
|
|
106
|
+
value,
|
|
107
|
+
pos
|
|
108
|
+
}) => /*#__PURE__*/_jsx("line", {
|
|
109
|
+
x1: pos,
|
|
110
|
+
x2: pos,
|
|
111
|
+
y1: 0,
|
|
112
|
+
y2: height,
|
|
113
|
+
...{
|
|
114
|
+
className: "x113i6qz xnpr05h"
|
|
115
|
+
}
|
|
116
|
+
}, `v-${value}`))]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LegendItem } from './legend';
|
|
2
|
+
export type { LegendItem };
|
|
3
|
+
export type LegendPosition = 'top' | 'bottom' | 'start' | 'end';
|
|
4
|
+
export type LegendAlignment = 'start' | 'center' | 'end';
|
|
5
|
+
export interface ChartLegendProps {
|
|
6
|
+
/** Legend items to display */
|
|
7
|
+
items?: LegendItem[];
|
|
8
|
+
/** Position of the legend relative to the chart. Default: 'bottom' */
|
|
9
|
+
position?: LegendPosition;
|
|
10
|
+
/** Alignment of the legend within its position. Default: 'start' */
|
|
11
|
+
alignment?: LegendAlignment;
|
|
12
|
+
}
|
|
13
|
+
export declare function ChartLegend({ items, position, alignment, }: ChartLegendProps): import("react").JSX.Element | null;
|
|
14
|
+
//# sourceMappingURL=ChartLegend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartLegend.d.ts","sourceRoot":"","sources":["../src/ChartLegend.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AAEzC,YAAY,EAAC,UAAU,EAAC,CAAC;AAEzB,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;AAChE,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,oEAAoE;IACpE,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAU,EACV,QAAmB,EACnB,SAAmB,GACpB,EAAE,gBAAgB,sCAsClB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ChartLegend.tsx
|
|
5
|
+
* @output Standalone chart legend component
|
|
6
|
+
* @position Can be used inside Chart via the `legend` prop, or independently
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // Via Chart
|
|
10
|
+
* <Chart legend={{position: 'top', alignment: 'start'}} ... />
|
|
11
|
+
*
|
|
12
|
+
* // Standalone
|
|
13
|
+
* <ChartLegend items={[{label: 'Revenue', color: '#3b82f6'}]} />
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { Text } from '@pharos-ds/core';
|
|
17
|
+
import { VStack, HStack } from '@pharos-ds/core';
|
|
18
|
+
import { ChartSwatch, swatchVariantForType } from "./ChartSwatch.js";
|
|
19
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
20
|
+
export function ChartLegend({
|
|
21
|
+
items = [],
|
|
22
|
+
position = 'bottom',
|
|
23
|
+
alignment = 'start'
|
|
24
|
+
}) {
|
|
25
|
+
if (items.length === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const isVertical = position === 'start' || position === 'end';
|
|
29
|
+
|
|
30
|
+
// Rows are stateless, but labels aren't guaranteed unique (two series can
|
|
31
|
+
// share a label), so disambiguate with the index to keep keys collision-free.
|
|
32
|
+
const legendItems = items.map((item, i) => /*#__PURE__*/_jsxs(HStack, {
|
|
33
|
+
gap: 2,
|
|
34
|
+
vAlign: "center",
|
|
35
|
+
role: "listitem",
|
|
36
|
+
children: [/*#__PURE__*/_jsx(ChartSwatch, {
|
|
37
|
+
color: item.color,
|
|
38
|
+
variant: swatchVariantForType(item.type)
|
|
39
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
40
|
+
type: "supporting",
|
|
41
|
+
children: item.label
|
|
42
|
+
})]
|
|
43
|
+
}, `${item.label}-${i}`));
|
|
44
|
+
if (isVertical) {
|
|
45
|
+
return /*#__PURE__*/_jsx(VStack, {
|
|
46
|
+
gap: 2,
|
|
47
|
+
hAlign: alignment,
|
|
48
|
+
role: "list",
|
|
49
|
+
"aria-label": "Chart legend",
|
|
50
|
+
children: legendItems
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return /*#__PURE__*/_jsx(HStack, {
|
|
54
|
+
gap: 4,
|
|
55
|
+
justify: alignment,
|
|
56
|
+
vAlign: "center",
|
|
57
|
+
wrap: "wrap",
|
|
58
|
+
role: "list",
|
|
59
|
+
"aria-label": "Chart legend",
|
|
60
|
+
children: legendItems
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visual variant — drives shape.
|
|
3
|
+
* - `'square'` — square chip (bar series)
|
|
4
|
+
* - `'line'` — short stroke (line, dot, area, and other non-bar series)
|
|
5
|
+
*/
|
|
6
|
+
export type ChartSwatchVariant = 'square' | 'line';
|
|
7
|
+
export interface ChartSwatchProps {
|
|
8
|
+
/** Fill color — typically a series color token */
|
|
9
|
+
color: string;
|
|
10
|
+
/** Visual variant. Default: `'square'`. */
|
|
11
|
+
variant?: ChartSwatchVariant;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Color swatch primitive.
|
|
15
|
+
*
|
|
16
|
+
* Used by ChartLegend (and ChartTooltip) to render the colored
|
|
17
|
+
* indicator next to a series label. Exported as a primitive so consumers
|
|
18
|
+
* can build their own custom legend/tooltip layouts while keeping visuals
|
|
19
|
+
* consistent.
|
|
20
|
+
*/
|
|
21
|
+
declare function ChartSwatchImpl({ color, variant }: ChartSwatchProps): import("react").JSX.Element;
|
|
22
|
+
/**
|
|
23
|
+
* Memoized — swatches are static for a given (color, variant) tuple
|
|
24
|
+
* and can render many times in a tooltip/legend with several series.
|
|
25
|
+
*/
|
|
26
|
+
export declare const ChartSwatch: import("react").MemoExoticComponent<typeof ChartSwatchImpl>;
|
|
27
|
+
/**
|
|
28
|
+
* Map a SeriesDef.type string to its swatch variant.
|
|
29
|
+
*
|
|
30
|
+
* Bar series get a square chip; everything else (line, dot, area, and any
|
|
31
|
+
* other non-bar mark) gets a short stroke. Centralized so legend, tooltip,
|
|
32
|
+
* and any custom chrome stay consistent.
|
|
33
|
+
*/
|
|
34
|
+
export declare function swatchVariantForType(type: string | undefined): ChartSwatchVariant;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=ChartSwatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartSwatch.d.ts","sourceRoot":"","sources":["../src/ChartSwatch.tsx"],"names":[],"mappings":"AAmBA;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAuBD;;;;;;;GAOG;AACH,iBAAS,eAAe,CAAC,EAAC,KAAK,EAAE,OAAkB,EAAC,EAAE,gBAAgB,+BAOrE;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,6DAAwB,CAAC;AAEjD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,kBAAkB,CAEpB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ChartSwatch.tsx
|
|
5
|
+
* @output Color swatch primitive for legends, tooltips, and standalone use
|
|
6
|
+
* @position Composable primitive — used by ChartLegend (and future
|
|
7
|
+
* ChartTooltip), or independently anywhere a series indicator
|
|
8
|
+
* is needed.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```
|
|
12
|
+
* <ChartSwatch color="#3b82f6" variant="square" />
|
|
13
|
+
* <ChartSwatch color="#f59e0b" variant="line" />
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { memo } from 'react';
|
|
18
|
+
import * as stylex from '@stylexjs/stylex';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Visual variant — drives shape.
|
|
22
|
+
* - `'square'` — square chip (bar series)
|
|
23
|
+
* - `'line'` — short stroke (line, dot, area, and other non-bar series)
|
|
24
|
+
*/
|
|
25
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
26
|
+
const styles = {
|
|
27
|
+
base: {
|
|
28
|
+
kmuXW: "x2lah0s",
|
|
29
|
+
$$css: true
|
|
30
|
+
},
|
|
31
|
+
square: {
|
|
32
|
+
kzqmXN: "x1xc55vz",
|
|
33
|
+
kZKoxP: "xdk7pt",
|
|
34
|
+
kaIpWk: "x1cum3z5",
|
|
35
|
+
kUOVxO: "xckhbgb",
|
|
36
|
+
$$css: true
|
|
37
|
+
},
|
|
38
|
+
line: {
|
|
39
|
+
kzqmXN: "x1fsd2vl",
|
|
40
|
+
kZKoxP: "xuoj239",
|
|
41
|
+
kaIpWk: "xbvija",
|
|
42
|
+
$$css: true
|
|
43
|
+
},
|
|
44
|
+
fill: color => [{
|
|
45
|
+
kWkggS: color != null ? "xl8spv7" : color,
|
|
46
|
+
$$css: true
|
|
47
|
+
}, {
|
|
48
|
+
"--x-backgroundColor": color != null ? color : undefined
|
|
49
|
+
}]
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Color swatch primitive.
|
|
54
|
+
*
|
|
55
|
+
* Used by ChartLegend (and ChartTooltip) to render the colored
|
|
56
|
+
* indicator next to a series label. Exported as a primitive so consumers
|
|
57
|
+
* can build their own custom legend/tooltip layouts while keeping visuals
|
|
58
|
+
* consistent.
|
|
59
|
+
*/
|
|
60
|
+
function ChartSwatchImpl({
|
|
61
|
+
color,
|
|
62
|
+
variant = 'square'
|
|
63
|
+
}) {
|
|
64
|
+
return /*#__PURE__*/_jsx("div", {
|
|
65
|
+
"aria-hidden": true,
|
|
66
|
+
...stylex.props(styles.base, styles[variant], styles.fill(color))
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Memoized — swatches are static for a given (color, variant) tuple
|
|
72
|
+
* and can render many times in a tooltip/legend with several series.
|
|
73
|
+
*/
|
|
74
|
+
export const ChartSwatch = /*#__PURE__*/memo(ChartSwatchImpl);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Map a SeriesDef.type string to its swatch variant.
|
|
78
|
+
*
|
|
79
|
+
* Bar series get a square chip; everything else (line, dot, area, and any
|
|
80
|
+
* other non-bar mark) gets a short stroke. Centralized so legend, tooltip,
|
|
81
|
+
* and any custom chrome stay consistent.
|
|
82
|
+
*/
|
|
83
|
+
export function swatchVariantForType(type) {
|
|
84
|
+
return type === 'bar' ? 'square' : 'line';
|
|
85
|
+
}
|