basalt-ui 1.13.0 → 1.15.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 (180) 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 +260 -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/configs/oxlint-plugin.js +152 -0
  9. package/configs/oxlint-plugin.test.ts +107 -0
  10. package/configs/oxlint.json +2 -0
  11. package/dist/charts/cursor/resolve.d.ts +33 -0
  12. package/dist/charts/cursor/resolve.d.ts.map +1 -0
  13. package/dist/charts/cursor/resolve.js +61 -0
  14. package/dist/charts/cursor/resolve.test.d.ts +2 -0
  15. package/dist/charts/cursor/resolve.test.d.ts.map +1 -0
  16. package/dist/charts/cursor/scope.d.ts +17 -0
  17. package/dist/charts/cursor/scope.d.ts.map +1 -0
  18. package/dist/charts/cursor/scope.js +20 -0
  19. package/dist/charts/cursor/store.d.ts +31 -0
  20. package/dist/charts/cursor/store.d.ts.map +1 -0
  21. package/dist/charts/cursor/store.js +25 -0
  22. package/dist/charts/cursor/store.test.d.ts +2 -0
  23. package/dist/charts/cursor/store.test.d.ts.map +1 -0
  24. package/dist/charts/hooks/useChartCursor.d.ts +39 -0
  25. package/dist/charts/hooks/useChartCursor.d.ts.map +1 -0
  26. package/dist/charts/hooks/useChartCursor.js +104 -0
  27. package/dist/charts/hooks/useChartSize.d.ts +8 -4
  28. package/dist/charts/hooks/useChartSize.d.ts.map +1 -1
  29. package/dist/charts/index.d.ts +16 -13
  30. package/dist/charts/index.d.ts.map +1 -1
  31. package/dist/charts/index.js +38 -19
  32. package/dist/charts/kinds/Bars.d.ts +25 -47
  33. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  34. package/dist/charts/kinds/Bars.js +230 -390
  35. package/dist/charts/kinds/Donut.d.ts +5 -4
  36. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  37. package/dist/charts/kinds/Donut.js +17 -14
  38. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  39. package/dist/charts/kinds/DualPanel.js +136 -90
  40. package/dist/charts/kinds/Heatmap.d.ts +15 -11
  41. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  42. package/dist/charts/kinds/Heatmap.js +38 -22
  43. package/dist/charts/kinds/MultiLine.d.ts +27 -35
  44. package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
  45. package/dist/charts/kinds/MultiLine.js +114 -237
  46. package/dist/charts/kinds/StackedArea.d.ts +21 -10
  47. package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
  48. package/dist/charts/kinds/StackedArea.js +74 -132
  49. package/dist/charts/kinds/ZonedLine.d.ts +24 -40
  50. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  51. package/dist/charts/kinds/ZonedLine.js +103 -184
  52. package/dist/charts/layout/auto-margin.d.ts +60 -0
  53. package/dist/charts/layout/auto-margin.d.ts.map +1 -0
  54. package/dist/charts/layout/auto-margin.js +37 -0
  55. package/dist/charts/layout/auto-margin.test.d.ts +2 -0
  56. package/dist/charts/layout/auto-margin.test.d.ts.map +1 -0
  57. package/dist/charts/primitives/CartesianChart.d.ts +143 -0
  58. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -0
  59. package/dist/charts/primitives/CartesianChart.js +349 -0
  60. package/dist/charts/primitives/CartesianChart.test.d.ts +2 -0
  61. package/dist/charts/primitives/CartesianChart.test.d.ts.map +1 -0
  62. package/dist/charts/primitives/ChartFrame.d.ts +16 -5
  63. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  64. package/dist/charts/primitives/ChartFrame.js +17 -2
  65. package/dist/charts/primitives/ChartLegend.d.ts +12 -1
  66. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  67. package/dist/charts/primitives/ChartLegend.js +21 -3
  68. package/dist/charts/primitives/ChartLegend.test.d.ts +2 -0
  69. package/dist/charts/primitives/ChartLegend.test.d.ts.map +1 -0
  70. package/dist/charts/primitives/ChartTooltip.d.ts +16 -16
  71. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  72. package/dist/charts/primitives/ChartTooltip.js +45 -19
  73. package/dist/charts/primitives/HoverOverlay.d.ts +19 -4
  74. package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
  75. package/dist/charts/primitives/HoverOverlay.js +22 -1
  76. package/dist/charts/primitives/XZoneRects.d.ts +40 -0
  77. package/dist/charts/primitives/XZoneRects.d.ts.map +1 -0
  78. package/dist/charts/primitives/XZoneRects.js +28 -0
  79. package/dist/charts/primitives/XZoneRects.test.d.ts +2 -0
  80. package/dist/charts/primitives/XZoneRects.test.d.ts.map +1 -0
  81. package/dist/charts/series.d.ts +16 -1
  82. package/dist/charts/series.d.ts.map +1 -1
  83. package/dist/charts/series.js +3 -1
  84. package/dist/charts/series.test.d.ts +2 -0
  85. package/dist/charts/series.test.d.ts.map +1 -0
  86. package/dist/charts/utils/measure-text.d.ts +25 -0
  87. package/dist/charts/utils/measure-text.d.ts.map +1 -0
  88. package/dist/charts/utils/measure-text.js +64 -0
  89. package/dist/charts/utils/measure-text.test.d.ts +2 -0
  90. package/dist/charts/utils/measure-text.test.d.ts.map +1 -0
  91. package/dist/content/fence-block.d.ts.map +1 -1
  92. package/dist/shell/app-sidebar.d.ts +19 -1
  93. package/dist/shell/app-sidebar.d.ts.map +1 -1
  94. package/dist/shell/app-sidebar.js +30 -26
  95. package/dist/shell/app-sidebar.module.css +11 -0
  96. package/dist/shell/app-sidebar.module.css.d.ts +1 -0
  97. package/dist/shell/app-sidebar.test.d.ts +2 -0
  98. package/dist/shell/app-sidebar.test.d.ts.map +1 -0
  99. package/dist/shell/index.d.ts +10 -1
  100. package/dist/shell/index.d.ts.map +1 -1
  101. package/dist/shell/index.js +2 -0
  102. package/dist/shell/index.test.d.ts +2 -0
  103. package/dist/shell/index.test.d.ts.map +1 -0
  104. package/dist/surfaces.d.ts +1 -1
  105. package/dist/surfaces.d.ts.map +1 -1
  106. package/dist/surfaces.js +1 -1
  107. package/dist/tokens/chart-margin.test.d.ts +2 -0
  108. package/dist/tokens/chart-margin.test.d.ts.map +1 -0
  109. package/dist/tokens/index.d.ts +29 -0
  110. package/dist/tokens/index.d.ts.map +1 -1
  111. package/dist/tokens/index.js +10 -0
  112. package/dist/tokens/palette.d.ts +4 -0
  113. package/dist/tokens/palette.d.ts.map +1 -1
  114. package/dist/tokens/palette.js +3 -0
  115. package/llms.txt +3 -3
  116. package/package.json +1 -1
  117. package/src/charts/cursor/resolve.test.ts +61 -0
  118. package/src/charts/cursor/resolve.ts +102 -0
  119. package/src/charts/cursor/scope.tsx +32 -0
  120. package/src/charts/cursor/store.test.ts +46 -0
  121. package/src/charts/cursor/store.ts +53 -0
  122. package/src/charts/hooks/useChartCursor.ts +163 -0
  123. package/src/charts/hooks/useChartSize.ts +8 -4
  124. package/src/charts/index.ts +34 -14
  125. package/src/charts/kinds/Bars.tsx +327 -460
  126. package/src/charts/kinds/Donut.tsx +31 -23
  127. package/src/charts/kinds/DualPanel.tsx +228 -134
  128. package/src/charts/kinds/Heatmap.tsx +72 -47
  129. package/src/charts/kinds/MultiLine.tsx +158 -294
  130. package/src/charts/kinds/StackedArea.tsx +116 -175
  131. package/src/charts/kinds/ZonedLine.tsx +148 -255
  132. package/src/charts/layout/auto-margin.test.ts +42 -0
  133. package/src/charts/layout/auto-margin.ts +110 -0
  134. package/src/charts/primitives/CartesianChart.test.ts +99 -0
  135. package/src/charts/primitives/CartesianChart.tsx +566 -0
  136. package/src/charts/primitives/ChartFrame.test.tsx +33 -0
  137. package/src/charts/primitives/ChartFrame.tsx +40 -4
  138. package/src/charts/primitives/ChartLegend.test.tsx +48 -0
  139. package/src/charts/primitives/ChartLegend.tsx +45 -2
  140. package/src/charts/primitives/ChartTooltip.tsx +67 -37
  141. package/src/charts/primitives/HoverOverlay.tsx +39 -3
  142. package/src/charts/primitives/XZoneRects.test.tsx +63 -0
  143. package/src/charts/primitives/XZoneRects.tsx +67 -0
  144. package/src/charts/series.test.ts +61 -0
  145. package/src/charts/series.ts +18 -1
  146. package/src/charts/utils/measure-text.test.ts +36 -0
  147. package/src/charts/utils/measure-text.ts +109 -0
  148. package/src/content/fence-block.tsx +2 -3
  149. package/src/shell/app-sidebar.module.css +11 -0
  150. package/src/shell/app-sidebar.module.css.d.ts +1 -0
  151. package/src/shell/app-sidebar.test.tsx +98 -0
  152. package/src/shell/app-sidebar.tsx +22 -0
  153. package/src/shell/index.test.tsx +35 -0
  154. package/src/shell/index.tsx +11 -0
  155. package/src/surfaces.ts +2 -1
  156. package/src/theme/spacing.test.ts +2 -0
  157. package/src/tokens/chart-margin.test.ts +39 -0
  158. package/src/tokens/density.test.ts +1 -0
  159. package/src/tokens/index.ts +36 -0
  160. package/src/tokens/palette.ts +3 -0
  161. package/dist/charts/hooks/useChartTooltip.d.ts +0 -13
  162. package/dist/charts/hooks/useChartTooltip.d.ts.map +0 -1
  163. package/dist/charts/hooks/useChartTooltip.js +0 -26
  164. package/dist/charts/hooks/useHoverSync.d.ts +0 -46
  165. package/dist/charts/hooks/useHoverSync.d.ts.map +0 -1
  166. package/dist/charts/hooks/useHoverSync.js +0 -75
  167. package/dist/charts/hover-context.d.ts +0 -21
  168. package/dist/charts/hover-context.d.ts.map +0 -1
  169. package/dist/charts/hover-context.js +0 -12
  170. package/dist/charts/hover-sync.d.ts +0 -14
  171. package/dist/charts/hover-sync.d.ts.map +0 -1
  172. package/dist/charts/hover-sync.js +0 -17
  173. package/dist/charts/primitives/ResponsiveChart.d.ts +0 -45
  174. package/dist/charts/primitives/ResponsiveChart.d.ts.map +0 -1
  175. package/dist/charts/primitives/ResponsiveChart.js +0 -24
  176. package/src/charts/hooks/useChartTooltip.ts +0 -31
  177. package/src/charts/hooks/useHoverSync.ts +0 -152
  178. package/src/charts/hover-context.ts +0 -28
  179. package/src/charts/hover-sync.tsx +0 -37
  180. 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,6 +37,7 @@ 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
42
  ...b.formatValue !== void 0 && { formatValue: b.formatValue }
47
43
  })),
@@ -55,412 +51,256 @@ function BarsInner(props) {
55
51
  mark: "line",
56
52
  dash: ln.dashed ? "dashed" : "solid",
57
53
  strokeWidth: ln.strokeWidth ?? LINE_OVERLAY_STROKE_WIDTH,
54
+ ...ln.axisSide !== void 0 && { axis: ln.axisSide },
58
55
  getValue: (d) => getValue(d, ln.key),
59
56
  ...ln.formatValue !== void 0 && { formatValue: ln.formatValue }
60
57
  })),
61
58
  [lines, getValue]
62
59
  );
63
- const legendSeries = useMemo(
60
+ const series = useMemo(
64
61
  () => [...barSeries, ...lineSeries],
65
62
  [barSeries, lineSeries]
66
63
  );
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) {
64
+ const yConfig = useMemo(() => {
65
+ const base = y ?? {};
66
+ if (barLayout !== "stacked" || base.domain !== void 0 && base.domain !== "auto")
67
+ return base;
68
+ const pad = base.autoPad ?? 1.1;
69
+ return {
70
+ ...base,
71
+ // Visible-only, so a legend toggle shrinks the axis rather than leaving a gap.
72
+ domain: (rows, visible) => {
73
+ const shown = new Set(visible.map((s) => s.key));
74
+ let maxSum = 0;
75
+ let minSum = 0;
76
+ for (const d of rows) {
142
77
  let pos = 0;
143
78
  for (const b of positiveBars) {
79
+ if (!shown.has(b.key)) continue;
144
80
  const v = getValue(d, b.key);
145
81
  if (v !== null && !Number.isNaN(v) && v > 0) pos += v;
146
82
  }
147
83
  let neg = 0;
148
84
  for (const b of negativeBars) {
85
+ if (!shown.has(b.key)) continue;
149
86
  const v = getValue(d, b.key);
150
87
  if (v !== null && !Number.isNaN(v) && v > 0) neg -= v;
151
88
  }
152
89
  if (pos > maxSum) maxSum = pos;
153
90
  if (neg < minSum) minSum = neg;
154
91
  }
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);
92
+ for (const ln of lines) {
93
+ if ((ln.axisSide ?? "left") !== "left" || !shown.has(ln.key)) continue;
94
+ for (const d of rows) {
95
+ const v = getValue(d, ln.key);
160
96
  if (v === null || Number.isNaN(v)) continue;
161
97
  if (v > maxSum) maxSum = v;
98
+ if (v < minSum) minSum = v;
162
99
  }
163
100
  }
101
+ const upper = Math.max(maxSum, base.autoMaxFloor ?? maxSum) * pad;
102
+ const ceil = base.autoMinCeil ?? 0;
103
+ return [padAutoLower(Math.min(minSum, ceil), pad), upper];
164
104
  }
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(
105
+ };
106
+ }, [y, barLayout, positiveBars, negativeBars, lines, getValue]);
107
+ const mappedRefLines = useMemo(
108
+ () => refLines?.map((r) => ({
109
+ value: r.value,
110
+ color: r.color,
111
+ ...r.dashed !== void 0 && { dashed: r.dashed },
112
+ ...r.axisSide !== void 0 && { axis: r.axisSide }
113
+ })),
114
+ [refLines]
115
+ );
116
+ return /* @__PURE__ */ jsx(
117
+ CartesianChart,
228
118
  {
229
119
  data,
230
120
  chartId,
231
- getKey: getX,
232
- xScale,
233
- marginLeft: MARGIN.left
121
+ getX,
122
+ series,
123
+ y: yConfig,
124
+ ...y2 !== void 0 && { y2 },
125
+ ...xTicks !== void 0 && { xTicks },
126
+ ...zones !== void 0 && { zones },
127
+ ...mappedRefLines !== void 0 && { refLines: mappedRefLines },
128
+ ...height !== void 0 && { height },
129
+ ...legend !== void 0 && { legend },
130
+ ...tooltip !== void 0 && { tooltip },
131
+ ...margin !== void 0 && { margin },
132
+ ...ariaLabel !== void 0 && { ariaLabel },
133
+ ...isPending !== void 0 && { isPending },
134
+ children: (ctx) => /* @__PURE__ */ jsx(
135
+ BarsMarks,
136
+ {
137
+ getX,
138
+ getValue,
139
+ positiveBars,
140
+ negativeBars,
141
+ lines,
142
+ barWidthRatio,
143
+ barLayout,
144
+ ...barOpacity !== void 0 && { barOpacity },
145
+ ctx
146
+ }
147
+ )
234
148
  }
235
149
  );
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 = [];
150
+ }
151
+ function BarsMarks({
152
+ getX,
153
+ getValue,
154
+ positiveBars,
155
+ negativeBars,
156
+ lines,
157
+ barWidthRatio,
158
+ barLayout,
159
+ barOpacity,
160
+ ctx
161
+ }) {
162
+ const { data: rows, xScale, yScale, y2Scale, xMax, hidden, highlighted } = ctx;
163
+ const barGroups = useMemo(() => {
164
+ const scaleForSide2 = (side) => side === "right" && y2Scale ? y2Scale : yScale;
165
+ const dim2 = (key) => highlighted === null || highlighted === key ? 1 : 0.15;
166
+ const groupWidth = Math.max(xMax / Math.max(rows.length, 1) * barWidthRatio, 2);
167
+ const totalWeight = barLayout === "grouped" ? positiveBars.reduce((s, b) => s + (b.weight ?? 1), 0) || 1 : 1;
168
+ const groupedBarWidths = barLayout === "grouped" ? positiveBars.map((b) => Math.max(groupWidth * ((b.weight ?? 1) / totalWeight), 1)) : [];
169
+ const groupedBarOffsets = [];
248
170
  let cursor = 0;
249
171
  for (const w of groupedBarWidths) {
250
- out.push(cursor);
172
+ groupedBarOffsets.push(cursor);
251
173
  cursor += w;
252
174
  }
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
- );
175
+ return rows.map((d) => {
176
+ const cx = xScale(getX(d)) ?? 0;
177
+ const groupLeft = cx - groupWidth / 2;
178
+ const rects = [];
179
+ if (barLayout === "stacked") {
180
+ let posOffset = 0;
181
+ for (const b of positiveBars) {
182
+ if (hidden.has(b.key)) continue;
183
+ const v = getValue(d, b.key);
184
+ if (v === null || Number.isNaN(v) || v <= 0) continue;
185
+ const top = posOffset + v;
186
+ const yTop = yScale(top);
187
+ const yBottom = yScale(posOffset);
188
+ rects.push({
189
+ key: `${getX(d)}-${b.key}`,
190
+ x: groupLeft,
191
+ y: yTop,
192
+ width: groupWidth,
193
+ height: yBottom - yTop,
194
+ fill: b.color,
195
+ fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dim2(b.key)
359
196
  });
197
+ posOffset = top;
360
198
  }
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 }
199
+ let negOffset = 0;
200
+ for (const b of negativeBars) {
201
+ if (hidden.has(b.key)) continue;
202
+ const v = getValue(d, b.key);
203
+ if (v === null || Number.isNaN(v) || v <= 0) continue;
204
+ const top = negOffset + v;
205
+ const yTop = yScale(-negOffset);
206
+ const yBottom = yScale(-top);
207
+ rects.push({
208
+ key: `${getX(d)}-${b.key}-neg`,
209
+ x: groupLeft,
210
+ y: yTop,
211
+ width: groupWidth,
212
+ height: yBottom - yTop,
213
+ fill: b.color,
214
+ fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dim2(b.key)
215
+ });
216
+ negOffset = top;
424
217
  }
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,
218
+ } else {
219
+ positiveBars.forEach((b, i) => {
220
+ if (hidden.has(b.key)) return;
221
+ const v = getValue(d, b.key);
222
+ if (v === null || Number.isNaN(v) || v <= 0) return;
223
+ const scale = scaleForSide2(b.axisSide);
224
+ const yTop = scale(v);
225
+ const yBottom = scale(0);
226
+ rects.push({
227
+ key: `${getX(d)}-${b.key}`,
228
+ x: groupLeft + (groupedBarOffsets[i] ?? 0),
229
+ y: yTop,
230
+ width: groupedBarWidths[i] ?? 0,
231
+ height: yBottom - yTop,
232
+ fill: b.color,
233
+ fillOpacity: (barOpacity?.(d, b.key) ?? 0.85) * dim2(b.key)
234
+ });
235
+ });
236
+ }
237
+ return { rowKey: getX(d), rects };
238
+ });
239
+ }, [
240
+ rows,
241
+ xScale,
242
+ yScale,
243
+ y2Scale,
244
+ xMax,
245
+ hidden,
246
+ highlighted,
247
+ positiveBars,
248
+ negativeBars,
249
+ barLayout,
250
+ barWidthRatio,
251
+ barOpacity,
252
+ getX,
253
+ getValue
254
+ ]);
255
+ const lineValid = useMemo(() => {
256
+ const out = /* @__PURE__ */ new Map();
257
+ for (const ln of lines) {
258
+ const valid = [];
259
+ for (const d of rows) {
260
+ const v = getValue(d, ln.key);
261
+ if (v !== null && !Number.isNaN(v)) valid.push({ __d: d, __y: v });
262
+ }
263
+ out.set(ln.key, valid);
264
+ }
265
+ return out;
266
+ }, [lines, rows, getValue]);
267
+ const scaleForSide = (side) => side === "right" && y2Scale ? y2Scale : yScale;
268
+ const dim = (key) => highlighted === null || highlighted === key ? 1 : 0.15;
269
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
270
+ barGroups.map((group) => /* @__PURE__ */ jsx("g", { children: group.rects.map((r) => /* @__PURE__ */ jsx(
271
+ "rect",
272
+ {
273
+ x: r.x,
274
+ y: r.y,
275
+ width: r.width,
276
+ height: r.height,
277
+ rx: 1.4,
278
+ fill: r.fill,
279
+ fillOpacity: r.fillOpacity
280
+ },
281
+ r.key
282
+ )) }, `bars-${group.rowKey}`)),
283
+ lines.map((ln) => {
284
+ if (hidden.has(ln.key)) return null;
285
+ const scale = scaleForSide(ln.axisSide);
286
+ const valid = lineValid.get(ln.key) ?? [];
287
+ if (valid.length === 0) return null;
288
+ return /* @__PURE__ */ jsx(
289
+ LinePath,
432
290
  {
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
- ] }) })
291
+ data: valid,
292
+ x: (p) => xScale(getX(p.__d)) ?? 0,
293
+ y: (p) => scale(p.__y),
294
+ stroke: ln.color,
295
+ strokeWidth: ln.strokeWidth ?? LINE_OVERLAY_STROKE_WIDTH,
296
+ strokeDasharray: ln.dashed ? VX.dashArray : void 0,
297
+ strokeOpacity: dim(ln.key),
298
+ curve: curveMonotoneX
299
+ },
300
+ `line-${ln.key}`
301
+ );
302
+ }),
303
+ negativeBars.length > 0 && /* @__PURE__ */ jsx("line", { x1: 0, x2: xMax, y1: yScale(0), y2: yScale(0), stroke: VX.grid, strokeWidth: 1 })
464
304
  ] });
465
305
  }
466
306
  const Bars = memo(BarsInner);