basalt-ui 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/README.md +38 -2
  4. package/agent/rules/basalt-charts.md +279 -108
  5. package/agent/rules/basalt-mantine.md +4 -2
  6. package/agent/skills/basalt-charts/SKILL.md +114 -64
  7. package/agent/skills/basalt-design/SKILL.md +4 -3
  8. package/agent/templates/CLAUDE-block.md.tpl +9 -6
  9. package/configs/oxlint-plugin.js +152 -0
  10. package/configs/oxlint-plugin.test.ts +107 -0
  11. package/configs/oxlint.json +2 -0
  12. package/dist/charts/cursor/resolve.d.ts +33 -0
  13. package/dist/charts/cursor/resolve.d.ts.map +1 -0
  14. package/dist/charts/cursor/resolve.js +61 -0
  15. package/dist/charts/cursor/resolve.test.d.ts +2 -0
  16. package/dist/charts/cursor/resolve.test.d.ts.map +1 -0
  17. package/dist/charts/cursor/scope.d.ts +17 -0
  18. package/dist/charts/cursor/scope.d.ts.map +1 -0
  19. package/dist/charts/cursor/scope.js +20 -0
  20. package/dist/charts/cursor/store.d.ts +31 -0
  21. package/dist/charts/cursor/store.d.ts.map +1 -0
  22. package/dist/charts/cursor/store.js +25 -0
  23. package/dist/charts/cursor/store.test.d.ts +2 -0
  24. package/dist/charts/cursor/store.test.d.ts.map +1 -0
  25. package/dist/charts/hooks/useChartCursor.d.ts +39 -0
  26. package/dist/charts/hooks/useChartCursor.d.ts.map +1 -0
  27. package/dist/charts/hooks/useChartCursor.js +104 -0
  28. package/dist/charts/hooks/useChartSize.d.ts +8 -4
  29. package/dist/charts/hooks/useChartSize.d.ts.map +1 -1
  30. package/dist/charts/index.d.ts +16 -13
  31. package/dist/charts/index.d.ts.map +1 -1
  32. package/dist/charts/index.js +38 -19
  33. package/dist/charts/kinds/Bars.d.ts +45 -54
  34. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  35. package/dist/charts/kinds/Bars.js +235 -392
  36. package/dist/charts/kinds/Bars.test.d.ts +2 -0
  37. package/dist/charts/kinds/Bars.test.d.ts.map +1 -0
  38. package/dist/charts/kinds/Donut.d.ts +5 -4
  39. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  40. package/dist/charts/kinds/Donut.js +17 -14
  41. package/dist/charts/kinds/DualPanel.d.ts +13 -0
  42. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  43. package/dist/charts/kinds/DualPanel.js +185 -92
  44. package/dist/charts/kinds/DualPanel.test.d.ts +2 -0
  45. package/dist/charts/kinds/DualPanel.test.d.ts.map +1 -0
  46. package/dist/charts/kinds/Heatmap.d.ts +15 -11
  47. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  48. package/dist/charts/kinds/Heatmap.js +38 -22
  49. package/dist/charts/kinds/MultiLine.d.ts +27 -35
  50. package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
  51. package/dist/charts/kinds/MultiLine.js +122 -235
  52. package/dist/charts/kinds/MultiLine.test.d.ts +2 -0
  53. package/dist/charts/kinds/MultiLine.test.d.ts.map +1 -0
  54. package/dist/charts/kinds/StackedArea.d.ts +21 -10
  55. package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
  56. package/dist/charts/kinds/StackedArea.js +74 -132
  57. package/dist/charts/kinds/ZonedLine.d.ts +24 -40
  58. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  59. package/dist/charts/kinds/ZonedLine.js +104 -184
  60. package/dist/charts/kinds/ZonedLine.test.d.ts +2 -0
  61. package/dist/charts/kinds/ZonedLine.test.d.ts.map +1 -0
  62. package/dist/charts/layout/auto-margin.d.ts +60 -0
  63. package/dist/charts/layout/auto-margin.d.ts.map +1 -0
  64. package/dist/charts/layout/auto-margin.js +37 -0
  65. package/dist/charts/layout/auto-margin.test.d.ts +2 -0
  66. package/dist/charts/layout/auto-margin.test.d.ts.map +1 -0
  67. package/dist/charts/primitives/CartesianChart.d.ts +161 -0
  68. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -0
  69. package/dist/charts/primitives/CartesianChart.js +359 -0
  70. package/dist/charts/primitives/CartesianChart.test.d.ts +2 -0
  71. package/dist/charts/primitives/CartesianChart.test.d.ts.map +1 -0
  72. package/dist/charts/primitives/ChartFrame.d.ts +16 -5
  73. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  74. package/dist/charts/primitives/ChartFrame.js +17 -2
  75. package/dist/charts/primitives/ChartLegend.d.ts +15 -1
  76. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  77. package/dist/charts/primitives/ChartLegend.js +25 -3
  78. package/dist/charts/primitives/ChartLegend.test.d.ts +2 -0
  79. package/dist/charts/primitives/ChartLegend.test.d.ts.map +1 -0
  80. package/dist/charts/primitives/ChartTooltip.d.ts +16 -16
  81. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  82. package/dist/charts/primitives/ChartTooltip.js +45 -19
  83. package/dist/charts/primitives/HoverOverlay.d.ts +19 -4
  84. package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
  85. package/dist/charts/primitives/HoverOverlay.js +22 -1
  86. package/dist/charts/primitives/XZoneRects.d.ts +54 -0
  87. package/dist/charts/primitives/XZoneRects.d.ts.map +1 -0
  88. package/dist/charts/primitives/XZoneRects.js +65 -0
  89. package/dist/charts/primitives/XZoneRects.test.d.ts +2 -0
  90. package/dist/charts/primitives/XZoneRects.test.d.ts.map +1 -0
  91. package/dist/charts/series.d.ts +28 -3
  92. package/dist/charts/series.d.ts.map +1 -1
  93. package/dist/charts/series.js +5 -2
  94. package/dist/charts/series.test.d.ts +2 -0
  95. package/dist/charts/series.test.d.ts.map +1 -0
  96. package/dist/charts/utils/measure-text.d.ts +25 -0
  97. package/dist/charts/utils/measure-text.d.ts.map +1 -0
  98. package/dist/charts/utils/measure-text.js +64 -0
  99. package/dist/charts/utils/measure-text.test.d.ts +2 -0
  100. package/dist/charts/utils/measure-text.test.d.ts.map +1 -0
  101. package/dist/content/fence-block.d.ts.map +1 -1
  102. package/dist/surfaces.d.ts +1 -1
  103. package/dist/surfaces.d.ts.map +1 -1
  104. package/dist/surfaces.js +1 -1
  105. package/dist/tokens/chart-margin.test.d.ts +2 -0
  106. package/dist/tokens/chart-margin.test.d.ts.map +1 -0
  107. package/dist/tokens/index.d.ts +29 -0
  108. package/dist/tokens/index.d.ts.map +1 -1
  109. package/dist/tokens/index.js +10 -0
  110. package/dist/tokens/palette.d.ts +4 -0
  111. package/dist/tokens/palette.d.ts.map +1 -1
  112. package/dist/tokens/palette.js +3 -0
  113. package/llms.txt +3 -3
  114. package/package.json +1 -1
  115. package/src/charts/cursor/resolve.test.ts +61 -0
  116. package/src/charts/cursor/resolve.ts +102 -0
  117. package/src/charts/cursor/scope.tsx +32 -0
  118. package/src/charts/cursor/store.test.ts +46 -0
  119. package/src/charts/cursor/store.ts +53 -0
  120. package/src/charts/hooks/useChartCursor.ts +163 -0
  121. package/src/charts/hooks/useChartSize.ts +8 -4
  122. package/src/charts/index.ts +35 -14
  123. package/src/charts/kinds/Bars.test.tsx +98 -0
  124. package/src/charts/kinds/Bars.tsx +350 -467
  125. package/src/charts/kinds/Donut.tsx +31 -23
  126. package/src/charts/kinds/DualPanel.test.tsx +131 -0
  127. package/src/charts/kinds/DualPanel.tsx +301 -135
  128. package/src/charts/kinds/Heatmap.tsx +72 -47
  129. package/src/charts/kinds/MultiLine.test.tsx +37 -0
  130. package/src/charts/kinds/MultiLine.tsx +171 -290
  131. package/src/charts/kinds/StackedArea.tsx +116 -175
  132. package/src/charts/kinds/ZonedLine.test.tsx +37 -0
  133. package/src/charts/kinds/ZonedLine.tsx +149 -255
  134. package/src/charts/layout/auto-margin.test.ts +42 -0
  135. package/src/charts/layout/auto-margin.ts +110 -0
  136. package/src/charts/primitives/CartesianChart.test.tsx +160 -0
  137. package/src/charts/primitives/CartesianChart.tsx +598 -0
  138. package/src/charts/primitives/ChartFrame.test.tsx +33 -0
  139. package/src/charts/primitives/ChartFrame.tsx +40 -4
  140. package/src/charts/primitives/ChartLegend.test.tsx +78 -0
  141. package/src/charts/primitives/ChartLegend.tsx +52 -2
  142. package/src/charts/primitives/ChartTooltip.tsx +67 -37
  143. package/src/charts/primitives/HoverOverlay.tsx +39 -3
  144. package/src/charts/primitives/XZoneRects.test.tsx +123 -0
  145. package/src/charts/primitives/XZoneRects.tsx +132 -0
  146. package/src/charts/series.test.ts +112 -0
  147. package/src/charts/series.ts +33 -5
  148. package/src/charts/utils/measure-text.test.ts +36 -0
  149. package/src/charts/utils/measure-text.ts +109 -0
  150. package/src/content/fence-block.tsx +2 -3
  151. package/src/surfaces.ts +2 -1
  152. package/src/theme/spacing.test.ts +2 -0
  153. package/src/tokens/chart-margin.test.ts +39 -0
  154. package/src/tokens/density.test.ts +1 -0
  155. package/src/tokens/index.ts +36 -0
  156. package/src/tokens/palette.ts +3 -0
  157. package/dist/charts/hooks/useChartTooltip.d.ts +0 -13
  158. package/dist/charts/hooks/useChartTooltip.d.ts.map +0 -1
  159. package/dist/charts/hooks/useChartTooltip.js +0 -26
  160. package/dist/charts/hooks/useHoverSync.d.ts +0 -46
  161. package/dist/charts/hooks/useHoverSync.d.ts.map +0 -1
  162. package/dist/charts/hooks/useHoverSync.js +0 -75
  163. package/dist/charts/hover-context.d.ts +0 -21
  164. package/dist/charts/hover-context.d.ts.map +0 -1
  165. package/dist/charts/hover-context.js +0 -12
  166. package/dist/charts/hover-sync.d.ts +0 -14
  167. package/dist/charts/hover-sync.d.ts.map +0 -1
  168. package/dist/charts/hover-sync.js +0 -17
  169. package/dist/charts/primitives/ResponsiveChart.d.ts +0 -45
  170. package/dist/charts/primitives/ResponsiveChart.d.ts.map +0 -1
  171. package/dist/charts/primitives/ResponsiveChart.js +0 -24
  172. package/src/charts/hooks/useChartTooltip.ts +0 -31
  173. package/src/charts/hooks/useHoverSync.ts +0 -152
  174. package/src/charts/hover-context.ts +0 -28
  175. package/src/charts/hover-sync.tsx +0 -37
  176. package/src/charts/primitives/ResponsiveChart.tsx +0 -64
@@ -1,40 +1,35 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { curveMonotoneX } from "@visx/curve";
3
- import { GridRows } from "@visx/grid";
4
- import { Group } from "@visx/group";
5
- import { scaleLinear, scalePoint } from "@visx/scale";
6
3
  import { LinePath } from "@visx/shape";
7
- import { memo, useMemo, useState } from "react";
8
- import { AxisBottomDate, AxisLeftNumeric, AxisRightNumeric } from "../primitives/Axes.js";
9
- import {
10
- ChartTooltip,
11
- TooltipBody,
12
- TooltipHeader,
13
- TooltipRow,
14
- useTooltipStyles
15
- } from "../primitives/ChartTooltip.js";
16
- import { ChartFrame, resolveLegend } from "../primitives/ChartFrame.js";
17
- import { Crosshair, SeriesDot } from "../primitives/Crosshair.js";
18
- import { HoverOverlay } from "../primitives/HoverOverlay.js";
19
- import { ZoneRects } from "../primitives/ZoneRects.js";
20
- import { useHoverSync } from "../hooks/useHoverSync.js";
21
- import { deriveTooltipRows, LINE_OVERLAY_STROKE_WIDTH } from "../series.js";
4
+ import { memo, useMemo } from "react";
22
5
  import { VX } from "../../tokens/index.js";
6
+ import { CartesianChart } from "../primitives/CartesianChart.js";
7
+ import { LINE_OVERLAY_STROKE_WIDTH } from "../series.js";
23
8
  import { padAutoLower } from "../utils/domain.js";
24
- import { smartTicks, smartTicksEvery } from "../utils/ticks.js";
25
9
  function BarsInner(props) {
26
10
  const {
11
+ data,
12
+ height,
13
+ chartId,
14
+ getX,
15
+ getValue,
27
16
  positiveBars,
28
17
  negativeBars = [],
29
18
  lines = [],
30
- getValue,
31
- chartId,
32
- height,
19
+ zones,
20
+ refLines,
21
+ y,
22
+ y2,
23
+ barWidthRatio = 0.6,
24
+ barLayout = "stacked",
25
+ barOpacity,
26
+ xTicks,
27
+ tooltip,
28
+ margin,
33
29
  legend,
34
30
  ariaLabel,
35
31
  isPending
36
32
  } = props;
37
- const [highlightedKey, setHighlightedKey] = useState(null);
38
33
  const barSeries = useMemo(
39
34
  () => [...positiveBars, ...negativeBars].map((b) => ({
40
35
  key: b.key,
@@ -42,8 +37,10 @@ function BarsInner(props) {
42
37
  color: b.color,
43
38
  mark: "bar",
44
39
  fillOpacity: 0.85,
40
+ ...b.axisSide !== void 0 && { axis: b.axisSide },
45
41
  getValue: (d) => getValue(d, b.key),
46
- ...b.formatValue !== void 0 && { formatValue: b.formatValue }
42
+ ...b.formatValue !== void 0 && { formatValue: b.formatValue },
43
+ ...b.tooltip !== void 0 && { tooltip: b.tooltip }
47
44
  })),
48
45
  [positiveBars, negativeBars, getValue]
49
46
  );
@@ -55,412 +52,258 @@ function BarsInner(props) {
55
52
  mark: "line",
56
53
  dash: ln.dashed ? "dashed" : "solid",
57
54
  strokeWidth: ln.strokeWidth ?? LINE_OVERLAY_STROKE_WIDTH,
55
+ ...ln.axisSide !== void 0 && { axis: ln.axisSide },
58
56
  getValue: (d) => getValue(d, ln.key),
59
- ...ln.formatValue !== void 0 && { formatValue: ln.formatValue }
57
+ ...ln.formatValue !== void 0 && { formatValue: ln.formatValue },
58
+ ...ln.tooltip !== void 0 && { tooltip: ln.tooltip },
59
+ ...ln.strokeOpacity !== void 0 && { strokeOpacity: ln.strokeOpacity }
60
60
  })),
61
61
  [lines, getValue]
62
62
  );
63
- const legendSeries = useMemo(
63
+ const series = useMemo(
64
64
  () => [...barSeries, ...lineSeries],
65
65
  [barSeries, lineSeries]
66
66
  );
67
- return /* @__PURE__ */ jsx(
68
- ChartFrame,
69
- {
70
- series: legendSeries,
71
- chartId,
72
- ...height !== void 0 && { height },
73
- ...ariaLabel !== void 0 && { ariaLabel },
74
- ...isPending !== void 0 && { isPending },
75
- legend: resolveLegend(legend, {
76
- highlighted: highlightedKey,
77
- onHighlight: setHighlightedKey
78
- }),
79
- children: (plot) => /* @__PURE__ */ jsx(
80
- BarsPlot,
81
- {
82
- ...props,
83
- plot,
84
- highlightedKey,
85
- barSeries,
86
- lineSeries
87
- }
88
- )
89
- }
90
- );
91
- }
92
- function BarsPlot(props) {
93
- const {
94
- data,
95
- chartId,
96
- getX,
97
- getValue,
98
- positiveBars,
99
- negativeBars = [],
100
- lines = [],
101
- zones = [],
102
- refLines = [],
103
- leftAxis,
104
- rightAxis,
105
- barWidthRatio = 0.6,
106
- barLayout = "stacked",
107
- barOpacity,
108
- tooltipLabel,
109
- renderPrefixTooltipRows,
110
- renderExtraTooltipRows,
111
- hideBarTooltipRows = false,
112
- formatValue = (v) => String(Math.round(v)),
113
- numTicksX,
114
- marginLeft,
115
- plot,
116
- highlightedKey,
117
- barSeries,
118
- lineSeries
119
- } = props;
120
- const dimOpacity = (key) => highlightedKey === null || highlightedKey === key ? 1 : 0.15;
121
- const MARGIN = useMemo(
122
- () => ({
123
- ...VX.margin,
124
- left: marginLeft ?? VX.margin.left,
125
- right: rightAxis ? Math.max(VX.margin.right, 40) : VX.margin.right
126
- }),
127
- [rightAxis, marginLeft]
128
- );
129
- const xMax = plot.width - MARGIN.left - MARGIN.right;
130
- const yMax = plot.height - MARGIN.top - MARGIN.bottom;
131
- const xScale = useMemo(
132
- () => scalePoint({ domain: data.map(getX), range: [0, xMax], padding: 0.3 }),
133
- [data, xMax, getX]
134
- );
135
- const leftYScale = useMemo(() => {
136
- if (leftAxis.domain === "auto") {
137
- const autoPad = leftAxis.autoPad ?? 1.1;
138
- let maxSum = 0;
139
- let minSum = 0;
140
- if (barLayout === "stacked") {
141
- for (const d of data) {
67
+ const yConfig = useMemo(() => {
68
+ const base = y ?? {};
69
+ if (barLayout !== "stacked" || base.domain !== void 0 && base.domain !== "auto")
70
+ return base;
71
+ const pad = base.autoPad ?? 1.1;
72
+ return {
73
+ ...base,
74
+ // Visible-only, so a legend toggle shrinks the axis rather than leaving a gap.
75
+ domain: (rows, visible) => {
76
+ const shown = new Set(visible.map((s) => s.key));
77
+ let maxSum = 0;
78
+ let minSum = 0;
79
+ for (const d of rows) {
142
80
  let pos = 0;
143
81
  for (const b of positiveBars) {
82
+ if (!shown.has(b.key)) continue;
144
83
  const v = getValue(d, b.key);
145
84
  if (v !== null && !Number.isNaN(v) && v > 0) pos += v;
146
85
  }
147
86
  let neg = 0;
148
87
  for (const b of negativeBars) {
88
+ if (!shown.has(b.key)) continue;
149
89
  const v = getValue(d, b.key);
150
90
  if (v !== null && !Number.isNaN(v) && v > 0) neg -= v;
151
91
  }
152
92
  if (pos > maxSum) maxSum = pos;
153
93
  if (neg < minSum) minSum = neg;
154
94
  }
155
- } else {
156
- for (const d of data) {
157
- for (const b of positiveBars) {
158
- if ((b.axisSide ?? "left") !== "left") continue;
159
- const v = getValue(d, b.key);
95
+ for (const ln of lines) {
96
+ if ((ln.axisSide ?? "left") !== "left" || !shown.has(ln.key)) continue;
97
+ for (const d of rows) {
98
+ const v = getValue(d, ln.key);
160
99
  if (v === null || Number.isNaN(v)) continue;
161
100
  if (v > maxSum) maxSum = v;
101
+ if (v < minSum) minSum = v;
162
102
  }
163
103
  }
104
+ const upper = Math.max(maxSum, base.autoMaxFloor ?? maxSum) * pad;
105
+ const ceil = base.autoMinCeil ?? 0;
106
+ return [padAutoLower(Math.min(minSum, ceil), pad), upper];
164
107
  }
165
- for (const ln of lines) {
166
- if ((ln.axisSide ?? "left") !== "left") continue;
167
- for (const d of data) {
168
- const v = getValue(d, ln.key);
169
- if (v === null || Number.isNaN(v)) continue;
170
- if (v > maxSum) maxSum = v;
171
- if (v < minSum) minSum = v;
172
- }
173
- }
174
- const upper = Math.max(maxSum, leftAxis.autoMaxFloor ?? maxSum) * autoPad;
175
- const ceil = leftAxis.autoMinCeil ?? 0;
176
- const lower = padAutoLower(Math.min(minSum, ceil), autoPad);
177
- return scaleLinear({ domain: [lower, upper], range: [yMax, 0], nice: true });
178
- }
179
- return scaleLinear({ domain: leftAxis.domain, range: [yMax, 0] });
180
- }, [data, leftAxis, positiveBars, negativeBars, lines, getValue, yMax, barLayout]);
181
- const rightYScale = useMemo(() => {
182
- if (!rightAxis) return null;
183
- if (rightAxis.domain === "auto") {
184
- const autoPad = rightAxis.autoPad ?? 1.1;
185
- let max = -Infinity;
186
- let min = Infinity;
187
- if (barLayout === "grouped") {
188
- for (const d of data) {
189
- for (const b of positiveBars) {
190
- if ((b.axisSide ?? "left") !== "right") continue;
191
- const v = getValue(d, b.key);
192
- if (v === null || Number.isNaN(v)) continue;
193
- if (v > max) max = v;
194
- if (v < min) min = v;
195
- }
196
- }
197
- }
198
- for (const ln of lines) {
199
- if ((ln.axisSide ?? "left") !== "right") continue;
200
- for (const d of data) {
201
- const v = getValue(d, ln.key);
202
- if (v === null || Number.isNaN(v)) continue;
203
- if (v > max) max = v;
204
- if (v < min) min = v;
205
- }
206
- }
207
- for (const z of zones) {
208
- if ((z.axisSide ?? "left") !== "right") continue;
209
- if (Number.isFinite(z.to) && z.to > max) max = z.to;
210
- if (Number.isFinite(z.from) && z.from < min) min = z.from;
211
- }
212
- for (const r of refLines) {
213
- if ((r.axisSide ?? "left") !== "right") continue;
214
- if (r.value > max) max = r.value;
215
- if (r.value < min) min = r.value;
216
- }
217
- const safeMax = Number.isFinite(max) ? max : 0;
218
- const safeMin = Number.isFinite(min) ? min : 0;
219
- const upper = Math.max(safeMax, rightAxis.autoMaxFloor ?? safeMax) * autoPad;
220
- const ceil = rightAxis.autoMinCeil ?? 0;
221
- const lower = padAutoLower(Math.min(safeMin, ceil), autoPad);
222
- return scaleLinear({ domain: [lower, upper], range: [yMax, 0], nice: true });
223
- }
224
- return scaleLinear({ domain: rightAxis.domain, range: [yMax, 0] });
225
- }, [data, rightAxis, lines, zones, refLines, positiveBars, getValue, yMax, barLayout]);
226
- const tooltipStyles = useTooltipStyles();
227
- const { tip, tooltipRef, syncedPoint, isDirectHover, handleMouse, handleLeave } = useHoverSync(
108
+ };
109
+ }, [y, barLayout, positiveBars, negativeBars, lines, getValue]);
110
+ const mappedRefLines = useMemo(
111
+ () => refLines?.map((r) => ({
112
+ value: r.value,
113
+ color: r.color,
114
+ ...r.dashed !== void 0 && { dashed: r.dashed },
115
+ ...r.axisSide !== void 0 && { axis: r.axisSide }
116
+ })),
117
+ [refLines]
118
+ );
119
+ return /* @__PURE__ */ jsx(
120
+ CartesianChart,
228
121
  {
229
122
  data,
230
123
  chartId,
231
- getKey: getX,
232
- xScale,
233
- marginLeft: MARGIN.left
124
+ getX,
125
+ series,
126
+ y: yConfig,
127
+ ...y2 !== void 0 && { y2 },
128
+ ...xTicks !== void 0 && { xTicks },
129
+ ...zones !== void 0 && { zones },
130
+ ...mappedRefLines !== void 0 && { refLines: mappedRefLines },
131
+ ...height !== void 0 && { height },
132
+ ...legend !== void 0 && { legend },
133
+ ...tooltip !== void 0 && { tooltip },
134
+ ...margin !== void 0 && { margin },
135
+ ...ariaLabel !== void 0 && { ariaLabel },
136
+ ...isPending !== void 0 && { isPending },
137
+ children: (ctx) => /* @__PURE__ */ jsx(
138
+ BarsMarks,
139
+ {
140
+ getX,
141
+ getValue,
142
+ positiveBars,
143
+ negativeBars,
144
+ lines,
145
+ barWidthRatio,
146
+ barLayout,
147
+ ...barOpacity !== void 0 && { barOpacity },
148
+ ctx
149
+ }
150
+ )
234
151
  }
235
152
  );
236
- const tickValues = useMemo(
237
- () => numTicksX ? smartTicksEvery(data.map(getX), numTicksX) : smartTicks(data.map(getX), xMax),
238
- [data, xMax, getX, numTicksX]
239
- );
240
- const groupWidth = Math.max(xMax / Math.max(data.length, 1) * barWidthRatio, 2);
241
- const groupedBarWidths = useMemo(() => {
242
- if (barLayout !== "grouped") return [];
243
- const totalWeight = positiveBars.reduce((s, b) => s + (b.weight ?? 1), 0) || 1;
244
- return positiveBars.map((b) => Math.max(groupWidth * ((b.weight ?? 1) / totalWeight), 1));
245
- }, [positiveBars, groupWidth, barLayout]);
246
- const groupedBarOffsets = useMemo(() => {
247
- const out = [];
153
+ }
154
+ function BarsMarks({
155
+ getX,
156
+ getValue,
157
+ positiveBars,
158
+ negativeBars,
159
+ lines,
160
+ barWidthRatio,
161
+ barLayout,
162
+ barOpacity,
163
+ ctx
164
+ }) {
165
+ const { data: rows, xScale, yScale, y2Scale, xMax, hidden, highlighted } = ctx;
166
+ const barGroups = useMemo(() => {
167
+ const scaleForSide2 = (side) => side === "right" && y2Scale ? y2Scale : yScale;
168
+ const dim2 = (key) => highlighted === null || highlighted === key ? 1 : 0.15;
169
+ const groupWidth = Math.max(xMax / Math.max(rows.length, 1) * barWidthRatio, 2);
170
+ const totalWeight = barLayout === "grouped" ? positiveBars.reduce((s, b) => s + (b.weight ?? 1), 0) || 1 : 1;
171
+ const groupedBarWidths = barLayout === "grouped" ? positiveBars.map((b) => Math.max(groupWidth * ((b.weight ?? 1) / totalWeight), 1)) : [];
172
+ const groupedBarOffsets = [];
248
173
  let cursor = 0;
249
174
  for (const w of groupedBarWidths) {
250
- out.push(cursor);
175
+ groupedBarOffsets.push(cursor);
251
176
  cursor += w;
252
177
  }
253
- return out;
254
- }, [groupedBarWidths]);
255
- const scaleFor = (side) => side === "right" && rightYScale ? rightYScale : leftYScale;
256
- const tooltipLbl = tip ? tooltipLabel?.(tip.data) ?? null : null;
257
- return /* @__PURE__ */ jsxs(Fragment, { children: [
258
- /* @__PURE__ */ jsx("svg", { width: plot.width, height: plot.height, children: /* @__PURE__ */ jsxs(Group, { left: MARGIN.left, top: MARGIN.top, children: [
259
- /* @__PURE__ */ jsx(
260
- GridRows,
261
- {
262
- scale: leftYScale,
263
- width: xMax,
264
- stroke: VX.grid,
265
- numTicks: leftAxis.numTicks ?? 5
266
- }
267
- ),
268
- /* @__PURE__ */ jsx(ZoneRects, { zones, width: xMax, leftScale: leftYScale, rightScale: rightYScale }),
269
- refLines.map((r, i) => {
270
- const scale = scaleFor(r.axisSide);
271
- return /* @__PURE__ */ jsx(
272
- "line",
273
- {
274
- x1: 0,
275
- x2: xMax,
276
- y1: scale(r.value),
277
- y2: scale(r.value),
278
- stroke: r.color,
279
- strokeDasharray: r.dashed ? VX.dashArray : void 0
280
- },
281
- `ref-${i}`
282
- );
283
- }),
284
- data.map((d) => {
285
- const cx = xScale(getX(d)) ?? 0;
286
- const groupLeft = cx - groupWidth / 2;
287
- const els = [];
288
- if (barLayout === "stacked") {
289
- let posOffset = 0;
290
- for (const b of positiveBars) {
291
- const v = getValue(d, b.key);
292
- if (v === null || Number.isNaN(v) || v <= 0) continue;
293
- const top = posOffset + v;
294
- const yTop = leftYScale(top);
295
- const yBottom = leftYScale(posOffset);
296
- els.push(
297
- /* @__PURE__ */ jsx(
298
- "rect",
299
- {
300
- x: groupLeft,
301
- y: yTop,
302
- width: groupWidth,
303
- height: yBottom - yTop,
304
- rx: 1.4,
305
- fill: b.color,
306
- fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dimOpacity(b.key)
307
- },
308
- `${getX(d)}-${b.key}`
309
- )
310
- );
311
- posOffset = top;
312
- }
313
- let negOffset = 0;
314
- for (const b of negativeBars) {
315
- const v = getValue(d, b.key);
316
- if (v === null || Number.isNaN(v) || v <= 0) continue;
317
- const top = negOffset + v;
318
- const yTop = leftYScale(-negOffset);
319
- const yBottom = leftYScale(-top);
320
- els.push(
321
- /* @__PURE__ */ jsx(
322
- "rect",
323
- {
324
- x: groupLeft,
325
- y: yTop,
326
- width: groupWidth,
327
- height: yBottom - yTop,
328
- rx: 1.4,
329
- fill: b.color,
330
- fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dimOpacity(b.key)
331
- },
332
- `${getX(d)}-${b.key}-neg`
333
- )
334
- );
335
- negOffset = top;
336
- }
337
- } else {
338
- positiveBars.forEach((b, i) => {
339
- const v = getValue(d, b.key);
340
- if (v === null || Number.isNaN(v) || v <= 0) return;
341
- const scale = scaleFor(b.axisSide);
342
- const yTop = scale(v);
343
- const yBottom = scale(0);
344
- els.push(
345
- /* @__PURE__ */ jsx(
346
- "rect",
347
- {
348
- x: groupLeft + (groupedBarOffsets[i] ?? 0),
349
- y: yTop,
350
- width: groupedBarWidths[i] ?? 0,
351
- height: yBottom - yTop,
352
- rx: 1.4,
353
- fill: b.color,
354
- fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dimOpacity(b.key)
355
- },
356
- `${getX(d)}-${b.key}`
357
- )
358
- );
178
+ return rows.map((d) => {
179
+ const cx = xScale(getX(d)) ?? 0;
180
+ const groupLeft = cx - groupWidth / 2;
181
+ const rects = [];
182
+ if (barLayout === "stacked") {
183
+ let posOffset = 0;
184
+ for (const b of positiveBars) {
185
+ if (hidden.has(b.key)) continue;
186
+ const v = getValue(d, b.key);
187
+ if (v === null || Number.isNaN(v) || v <= 0) continue;
188
+ const top = posOffset + v;
189
+ const yTop = yScale(top);
190
+ const yBottom = yScale(posOffset);
191
+ rects.push({
192
+ key: `${getX(d)}-${b.key}`,
193
+ x: groupLeft,
194
+ y: yTop,
195
+ width: groupWidth,
196
+ height: yBottom - yTop,
197
+ fill: b.color,
198
+ fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dim2(b.key)
359
199
  });
200
+ posOffset = top;
360
201
  }
361
- return /* @__PURE__ */ jsx("g", { children: els }, `bars-${getX(d)}`);
362
- }),
363
- lines.map((ln) => {
364
- const scale = scaleFor(ln.axisSide);
365
- const valid = [];
366
- for (const d of data) {
367
- const v = getValue(d, ln.key);
368
- if (v !== null && !Number.isNaN(v)) valid.push({ __d: d, __y: v });
369
- }
370
- if (valid.length === 0) return null;
371
- return /* @__PURE__ */ jsx(
372
- LinePath,
373
- {
374
- data: valid,
375
- x: (p) => xScale(getX(p.__d)) ?? 0,
376
- y: (p) => scale(p.__y),
377
- stroke: ln.color,
378
- strokeWidth: ln.strokeWidth ?? LINE_OVERLAY_STROKE_WIDTH,
379
- strokeDasharray: ln.dashed ? VX.dashArray : void 0,
380
- strokeOpacity: dimOpacity(ln.key),
381
- curve: curveMonotoneX
382
- },
383
- `line-${ln.key}`
384
- );
385
- }),
386
- negativeBars.length > 0 && /* @__PURE__ */ jsx(
387
- "line",
388
- {
389
- x1: 0,
390
- x2: xMax,
391
- y1: leftYScale(0),
392
- y2: leftYScale(0),
393
- stroke: VX.grid,
394
- strokeWidth: 1
395
- }
396
- ),
397
- syncedPoint && (() => {
398
- const sx = xScale(getX(syncedPoint)) ?? 0;
399
- return /* @__PURE__ */ jsxs(Fragment, { children: [
400
- /* @__PURE__ */ jsx(Crosshair, { x: sx, top: 0, bottom: yMax }),
401
- lines.map((ln) => {
402
- const v = getValue(syncedPoint, ln.key);
403
- if (v === null || Number.isNaN(v)) return null;
404
- const scale = scaleFor(ln.axisSide);
405
- return /* @__PURE__ */ jsx(SeriesDot, { cx: sx, cy: scale(v), color: ln.color }, `dot-${ln.key}`);
406
- })
407
- ] });
408
- })(),
409
- /* @__PURE__ */ jsx(
410
- AxisLeftNumeric,
411
- {
412
- scale: leftYScale,
413
- numTicks: leftAxis.numTicks ?? 5,
414
- ...leftAxis.formatTick !== void 0 && { tickFormat: leftAxis.formatTick }
415
- }
416
- ),
417
- rightYScale && rightAxis && /* @__PURE__ */ jsx(
418
- AxisRightNumeric,
419
- {
420
- scale: rightYScale,
421
- left: xMax,
422
- numTicks: rightAxis.numTicks ?? 5,
423
- ...rightAxis.formatTick !== void 0 && { tickFormat: rightAxis.formatTick }
202
+ let negOffset = 0;
203
+ for (const b of negativeBars) {
204
+ if (hidden.has(b.key)) continue;
205
+ const v = getValue(d, b.key);
206
+ if (v === null || Number.isNaN(v) || v <= 0) continue;
207
+ const top = negOffset + v;
208
+ const yTop = yScale(-negOffset);
209
+ const yBottom = yScale(-top);
210
+ rects.push({
211
+ key: `${getX(d)}-${b.key}-neg`,
212
+ x: groupLeft,
213
+ y: yTop,
214
+ width: groupWidth,
215
+ height: yBottom - yTop,
216
+ fill: b.color,
217
+ fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dim2(b.key)
218
+ });
219
+ negOffset = top;
424
220
  }
425
- ),
426
- /* @__PURE__ */ jsx(AxisBottomDate, { top: yMax, scale: xScale, tickValues }),
427
- /* @__PURE__ */ jsx(HoverOverlay, { width: xMax, height: yMax, onMove: handleMouse, onLeave: handleLeave })
428
- ] }) }),
429
- /* @__PURE__ */ jsx(ChartTooltip, { tip: isDirectHover ? tip : null, tooltipRef, styles: tooltipStyles, children: tip && isDirectHover && /* @__PURE__ */ jsxs(Fragment, { children: [
430
- /* @__PURE__ */ jsx(
431
- TooltipHeader,
221
+ } else {
222
+ positiveBars.forEach((b, i) => {
223
+ if (hidden.has(b.key)) return;
224
+ const v = getValue(d, b.key);
225
+ if (v === null || Number.isNaN(v) || v <= 0) return;
226
+ const scale = scaleForSide2(b.axisSide);
227
+ const yTop = scale(v);
228
+ const yBottom = scale(0);
229
+ rects.push({
230
+ key: `${getX(d)}-${b.key}`,
231
+ x: groupLeft + (groupedBarOffsets[i] ?? 0),
232
+ y: yTop,
233
+ width: groupedBarWidths[i] ?? 0,
234
+ height: yBottom - yTop,
235
+ fill: b.color,
236
+ fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dim2(b.key)
237
+ });
238
+ });
239
+ }
240
+ return { rowKey: getX(d), rects };
241
+ });
242
+ }, [
243
+ rows,
244
+ xScale,
245
+ yScale,
246
+ y2Scale,
247
+ xMax,
248
+ hidden,
249
+ highlighted,
250
+ positiveBars,
251
+ negativeBars,
252
+ barLayout,
253
+ barWidthRatio,
254
+ barOpacity,
255
+ getX,
256
+ getValue
257
+ ]);
258
+ const lineValid = useMemo(() => {
259
+ const out = /* @__PURE__ */ new Map();
260
+ for (const ln of lines) {
261
+ const valid = [];
262
+ for (const d of rows) {
263
+ const v = getValue(d, ln.key);
264
+ if (v !== null && !Number.isNaN(v)) valid.push({ __d: d, __y: v });
265
+ }
266
+ out.set(ln.key, valid);
267
+ }
268
+ return out;
269
+ }, [lines, rows, getValue]);
270
+ const scaleForSide = (side) => side === "right" && y2Scale ? y2Scale : yScale;
271
+ const dim = (key) => highlighted === null || highlighted === key ? 1 : 0.15;
272
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
273
+ barGroups.map((group) => /* @__PURE__ */ jsx("g", { children: group.rects.map((r) => /* @__PURE__ */ jsx(
274
+ "rect",
275
+ {
276
+ x: r.x,
277
+ y: r.y,
278
+ width: r.width,
279
+ height: r.height,
280
+ rx: 1.4,
281
+ fill: r.fill,
282
+ fillOpacity: r.fillOpacity
283
+ },
284
+ r.key
285
+ )) }, `bars-${group.rowKey}`)),
286
+ lines.map((ln) => {
287
+ if (hidden.has(ln.key)) return null;
288
+ const scale = scaleForSide(ln.axisSide);
289
+ const valid = lineValid.get(ln.key) ?? [];
290
+ if (valid.length === 0) return null;
291
+ return /* @__PURE__ */ jsx(
292
+ LinePath,
432
293
  {
433
- date: getX(tip.data),
434
- ...tooltipLbl !== null && { label: tooltipLbl.text, labelColor: tooltipLbl.color }
435
- }
436
- ),
437
- /* @__PURE__ */ jsxs(TooltipBody, { children: [
438
- renderPrefixTooltipRows?.(tip.data),
439
- !hideBarTooltipRows && deriveTooltipRows(barSeries, tip.data, formatValue).map((row) => /* @__PURE__ */ jsx(
440
- TooltipRow,
441
- {
442
- color: row.color,
443
- label: row.label,
444
- value: row.value,
445
- shape: row.shape
446
- },
447
- row.key
448
- )),
449
- deriveTooltipRows(lineSeries, tip.data, formatValue).map((row) => /* @__PURE__ */ jsx(
450
- TooltipRow,
451
- {
452
- color: row.color,
453
- label: row.label,
454
- value: row.value,
455
- shape: row.shape,
456
- dashed: row.dashed,
457
- ...row.strokeWidth !== void 0 && { strokeWidth: row.strokeWidth }
458
- },
459
- row.key
460
- )),
461
- renderExtraTooltipRows?.(tip.data)
462
- ] })
463
- ] }) })
294
+ data: valid,
295
+ x: (p) => xScale(getX(p.__d)) ?? 0,
296
+ y: (p) => scale(p.__y),
297
+ stroke: ln.color,
298
+ strokeWidth: ln.strokeWidth ?? LINE_OVERLAY_STROKE_WIDTH,
299
+ strokeDasharray: ln.dashed ? VX.dashArray : void 0,
300
+ strokeOpacity: dim(ln.key) * (ln.strokeOpacity ?? 1),
301
+ curve: curveMonotoneX
302
+ },
303
+ `line-${ln.key}`
304
+ );
305
+ }),
306
+ negativeBars.length > 0 && /* @__PURE__ */ jsx("line", { x1: 0, x2: xMax, y1: yScale(0), y2: yScale(0), stroke: VX.grid, strokeWidth: 1 })
464
307
  ] });
465
308
  }
466
309
  const Bars = memo(BarsInner);