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
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Bars.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bars.test.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Bars.test.tsx"],"names":[],"mappings":""}
@@ -52,10 +52,11 @@ export type DonutProps<K extends string = SeriesKey> = {
52
52
  /**
53
53
  * Radial slice-share chart with a punched-out center label. Composes `ChartFrame` for a
54
54
  * categorical legend derived from the slices (one `SeriesStyle` per slice, `mark: 'bar'`) so the
55
- * legend can never drift from what's plotted. No crosshair — meaningless for a radial layout.
56
- * Hover stays local to the pie (dimming siblings on hover) rather than joining the shared
57
- * `HoverContext`: a date-keyed cursor has no counterpart on a donut, and cross-kind category sync
58
- * (donut ↔ bar, via the generalized key) is a distinct, deliberately deferred feature.
55
+ * legend can never drift from what's plotted — legend-hidden slices drop out of the ring, the
56
+ * center total, and the tooltip's "Share" row together (`docs/CHARTS-SPEC.md` §5). No crosshair —
57
+ * meaningless for a radial layout. Hover stays local to the pie (dimming siblings on hover) rather
58
+ * than joining the shared cursor: a date-keyed cursor has no counterpart on a donut, and cross-kind
59
+ * category sync (donut ↔ bar, via a generalized key) is a distinct, deliberately deferred feature.
59
60
  */
60
61
  declare function DonutInner<K extends string = SeriesKey>(props: DonutProps<K>): import("react").JSX.Element;
61
62
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Donut.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Donut.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,IAAI;IAAE,GAAG,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,IAAI;IACrD,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAA;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAA;IAC/B,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;;GAOG;AACH,iBAAS,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,+BAoBrE;AAmJD;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAuB,OAAO,UAAU,CAAA"}
1
+ {"version":3,"file":"Donut.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Donut.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAKpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,IAAI;IAAE,GAAG,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,IAAI;IACrD,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAA;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAA;IAC/B,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;;;GAQG;AACH,iBAAS,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,+BAoBrE;AA2JD;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAuB,OAAO,UAAU,CAAA"}
@@ -1,10 +1,9 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Group } from "@visx/group";
3
3
  import { Pie } from "@visx/shape";
4
- import { memo, useMemo } from "react";
5
- import { ChartTooltip, TooltipBody, TooltipRow, useTooltipStyles } from "../primitives/ChartTooltip.js";
4
+ import { memo, useMemo, useState } from "react";
5
+ import { ChartTooltipFloat, TooltipBody, TooltipRow } from "../primitives/ChartTooltip.js";
6
6
  import { ChartFrame } from "../primitives/ChartFrame.js";
7
- import { useChartTooltip } from "../hooks/useChartTooltip.js";
8
7
  import { VX } from "../../tokens/index.js";
9
8
  function DonutInner(props) {
10
9
  const { data, height, colorForKey, seriesLabel = (k) => k, ariaLabel, isPending } = props;
@@ -38,21 +37,25 @@ function DonutPlot(props) {
38
37
  innerRatio = 0.6,
39
38
  padAngle = 0.01
40
39
  } = props;
41
- const { width, height } = plot;
42
- const tooltipStyles = useTooltipStyles();
43
- const { tip, show, hide, tooltipRef } = useChartTooltip();
44
- const hoveredKey = tip?.data.key ?? null;
40
+ const { width, height, hidden } = plot;
41
+ const [tip, setTip] = useState(null);
42
+ const hoveredKey = tip?.key ?? null;
43
+ const visibleData = useMemo(() => data.filter((d) => !hidden.has(d.key)), [data, hidden]);
45
44
  const radius = Math.min(width, height) / 2 - 4;
46
45
  const innerRadius = radius * innerRatio;
47
46
  const centerX = width / 2;
48
47
  const centerY = height / 2;
49
- const total = useMemo(() => data.reduce((sum, d) => sum + d.value, 0), [data]);
48
+ const total = useMemo(() => visibleData.reduce((sum, d) => sum + d.value, 0), [visibleData]);
49
+ const show = (d, event) => {
50
+ setTip({ key: d.key, value: d.value, anchor: { x: event.clientX, y: event.clientY } });
51
+ };
52
+ const hide = () => setTip(null);
50
53
  return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
51
54
  /* @__PURE__ */ jsx("svg", { width, height, children: /* @__PURE__ */ jsxs(Group, { left: centerX, top: centerY, children: [
52
55
  /* @__PURE__ */ jsx(
53
56
  Pie,
54
57
  {
55
- data,
58
+ data: visibleData,
56
59
  pieValue: (d) => d.value,
57
60
  pieSortValues: () => 0,
58
61
  outerRadius: radius,
@@ -135,13 +138,13 @@ function DonutPlot(props) {
135
138
  children: centerContent
136
139
  }
137
140
  ),
138
- /* @__PURE__ */ jsx(ChartTooltip, { tip, tooltipRef, styles: tooltipStyles, children: tip && /* @__PURE__ */ jsxs(TooltipBody, { children: [
141
+ tip !== null && /* @__PURE__ */ jsx(ChartTooltipFloat, { anchor: tip.anchor, children: /* @__PURE__ */ jsxs(TooltipBody, { children: [
139
142
  /* @__PURE__ */ jsx(
140
143
  TooltipRow,
141
144
  {
142
- color: colorForKey(tip.data.key),
143
- label: seriesLabel(tip.data.key),
144
- value: formatValue(tip.data.value),
145
+ color: colorForKey(tip.key),
146
+ label: seriesLabel(tip.key),
147
+ value: formatValue(tip.value),
145
148
  shape: "bar"
146
149
  }
147
150
  ),
@@ -150,7 +153,7 @@ function DonutPlot(props) {
150
153
  {
151
154
  color: VX.grid,
152
155
  label: "Share",
153
- value: `${total > 0 ? Math.round(tip.data.value / total * 100) : 0}%`,
156
+ value: `${total > 0 ? Math.round(tip.value / total * 100) : 0}%`,
154
157
  shape: "bar"
155
158
  }
156
159
  )
@@ -33,7 +33,20 @@ export type DualPanelProps<T> = {
33
33
  /** Top pane share of the inner plot height. Default 0.62. */
34
34
  topFraction?: number;
35
35
  formatTop: (v: number) => string;
36
+ /** Drives the bottom-pane TICKS. Also the tooltip-row fallback when `formatBar` is omitted. */
36
37
  formatBottom: (v: number) => string;
38
+ /** Per-row tooltip formatter for the bottom-pane bar — overrides `formatBottom` for the tooltip
39
+ * row only (ticks keep reading `formatBottom`). Receives the hovered datum alongside the value,
40
+ * so a row can add a unit/decimal `formatBottom` can't (e.g. a velocity reading). */
41
+ formatBar?: (v: number, d: T) => string;
42
+ /**
43
+ * Bottom-pane y-domain. Default `'auto'`: a symmetric `[-maxAbs, maxAbs]` computed from the
44
+ * data, `nice`d. A fixed tuple pins the domain instead (and is used verbatim, un-`nice`d).
45
+ */
46
+ bottomYDomain?: [number, number] | 'auto';
47
+ /** When `bottomYDomain` is `'auto'`: floors the symmetric max-abs so a plateau doesn't amplify
48
+ * to fill the whole pane (mirrors `AxisConfig.autoMaxFloor`). Ignored with a fixed tuple. */
49
+ bottomMaxAbsFloor?: number;
37
50
  /** Tooltip badge — appears at the right of the tooltip header. */
38
51
  tooltipLabel?: (d: T) => {
39
52
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"DualPanel.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/DualPanel.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAGvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAe,MAAM,WAAW,CAAA;AAI5E,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB;8DAC0D;IAC1D,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACxB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IACtC,2EAA2E;IAC3E,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACxD,wGAAwG;IACxG,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;IAClE,oDAAoD;IACpD,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAA;IACrB,8DAA8D;IAC9D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAChC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC,kEAAkE;IAClE,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC/D;4CACwC;IACxC,MAAM,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAA;IAClC,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAID;;;;;;;;;;;GAWG;AACH,iBAAS,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,+BAmClD;AA+TD;;;GAGG;AACH,eAAO,MAAM,SAAS,EAA2B,OAAO,cAAc,CAAA"}
1
+ {"version":3,"file":"DualPanel.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/DualPanel.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAIvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAe,MAAM,WAAW,CAAA;AAK5E,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB;8DAC0D;IAC1D,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACxB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IACtC,2EAA2E;IAC3E,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACxD,wGAAwG;IACxG,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;IAClE,oDAAoD;IACpD,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAA;IACrB,8DAA8D;IAC9D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAChC,+FAA+F;IAC/F,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC;;yFAEqF;IACrF,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACvC;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IACzC;iGAC6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,kEAAkE;IAClE,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC/D;4CACwC;IACxC,MAAM,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAA;IAClC,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAID;;;;;;;;;;;GAWG;AACH,iBAAS,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,+BAmClD;AAsdD;;;GAGG;AACH,eAAO,MAAM,SAAS,EAA2B,OAAO,cAAc,CAAA"}
@@ -8,19 +8,20 @@ import { Threshold } from "@visx/threshold";
8
8
  import { memo, useMemo } from "react";
9
9
  import { AxisBottomDate, AxisLeftNumeric } from "../primitives/Axes.js";
10
10
  import {
11
- ChartTooltip,
11
+ ChartTooltipFloat,
12
12
  TooltipBody,
13
13
  TooltipHeader,
14
- TooltipRow,
15
- useTooltipStyles
14
+ TooltipRow
16
15
  } from "../primitives/ChartTooltip.js";
17
16
  import { ChartFrame, resolveLegend } from "../primitives/ChartFrame.js";
18
17
  import { Crosshair, SeriesDot } from "../primitives/Crosshair.js";
19
18
  import { HoverOverlay } from "../primitives/HoverOverlay.js";
20
19
  import { ZoneRects } from "../primitives/ZoneRects.js";
21
- import { useHoverSync } from "../hooks/useHoverSync.js";
20
+ import { useChartCursor } from "../hooks/useChartCursor.js";
21
+ import { autoMargin, probeAxisLabels } from "../layout/auto-margin.js";
22
22
  import { deriveTooltipRows, LINE_OVERLAY_STROKE_WIDTH } from "../series.js";
23
23
  import { VX } from "../../tokens/index.js";
24
+ import { fmtAxisDate } from "../utils/format.js";
24
25
  import { smartTicks } from "../utils/ticks.js";
25
26
  const PANE_GAP = 12;
26
27
  function DualPanelInner(props) {
@@ -66,27 +67,21 @@ function DualPanelPlot(props) {
66
67
  topFraction = 0.62,
67
68
  formatTop,
68
69
  formatBottom,
70
+ formatBar,
71
+ bottomYDomain = "auto",
72
+ bottomMaxAbsFloor,
69
73
  tooltipLabel,
70
74
  plot
71
75
  } = props;
72
- const MARGIN = VX.margin;
73
- const xMax = plot.width - MARGIN.left - MARGIN.right;
74
- const plotH = plot.height - MARGIN.top - MARGIN.bottom - PANE_GAP;
75
- const topH = Math.max(Math.round(plotH * topFraction), 1);
76
- const bottomH = Math.max(plotH - topH, 1);
77
- const bottomTop = topH + PANE_GAP;
78
- const innerH = topH + PANE_GAP + bottomH;
79
- const xScale = useMemo(
80
- () => scalePoint({ domain: data.map(getX), range: [0, xMax], padding: 0.3 }),
81
- [data, xMax, getX]
82
- );
83
- const topYScale = useMemo(() => {
84
- if (topYDomain !== "auto") {
85
- return scaleLinear({ domain: topYDomain, range: [topH, 0] });
86
- }
76
+ const { hidden } = plot;
77
+ const visibleSeries = useMemo(() => series.filter((s) => !hidden.has(s.key)), [series, hidden]);
78
+ const barVisible = !hidden.has("__divergence");
79
+ const useNiceTop = topYDomain === "auto";
80
+ const topDomain = useMemo(() => {
81
+ if (topYDomain !== "auto") return topYDomain;
87
82
  let lo = Infinity;
88
83
  let hi = -Infinity;
89
- for (const s of series) {
84
+ for (const s of visibleSeries) {
90
85
  for (const d of data) {
91
86
  const v = s.getValue(d);
92
87
  if (v === null || v === void 0 || Number.isNaN(v)) continue;
@@ -99,43 +94,112 @@ function DualPanelPlot(props) {
99
94
  hi = 1;
100
95
  }
101
96
  const span = hi - lo || Math.abs(hi) || 1;
102
- return scaleLinear({
103
- domain: [lo - span * 0.08, hi + span * 0.08],
104
- range: [topH, 0],
105
- nice: true
106
- });
107
- }, [data, series, topYDomain, topH]);
108
- const bottomYScale = useMemo(() => {
109
- let maxAbs = 0;
97
+ return [lo - span * 0.08, hi + span * 0.08];
98
+ }, [data, visibleSeries, topYDomain]);
99
+ const topLabels = useMemo(
100
+ () => probeAxisLabels({ domain: topDomain, ticks: 4, format: formatTop, nice: useNiceTop }).labels,
101
+ [topDomain, useNiceTop, formatTop]
102
+ );
103
+ const useNiceBottom = bottomYDomain === "auto";
104
+ const maxAbs = useMemo(() => {
105
+ if (bottomYDomain !== "auto") return 0;
106
+ let m = 0;
110
107
  for (const d of data) {
111
108
  const v = getBar(d);
112
109
  if (v === null || v === void 0 || Number.isNaN(v)) continue;
113
110
  const a = Math.abs(v);
114
- if (a > maxAbs) maxAbs = a;
111
+ if (a > m) m = a;
115
112
  }
116
- if (maxAbs === 0) maxAbs = 1;
117
- return scaleLinear({
118
- domain: [-maxAbs, maxAbs],
113
+ const floored = bottomMaxAbsFloor !== void 0 ? Math.max(m, bottomMaxAbsFloor) : m;
114
+ return floored === 0 ? 1 : floored;
115
+ }, [data, getBar, bottomYDomain, bottomMaxAbsFloor]);
116
+ const bottomDomain = useMemo(
117
+ () => bottomYDomain === "auto" ? [-maxAbs, maxAbs] : bottomYDomain,
118
+ [bottomYDomain, maxAbs]
119
+ );
120
+ const bottomLabels = useMemo(
121
+ () => probeAxisLabels({
122
+ domain: bottomDomain,
123
+ ticks: 3,
124
+ format: formatBottom,
125
+ nice: useNiceBottom
126
+ }).labels,
127
+ [bottomDomain, formatBottom, useNiceBottom]
128
+ );
129
+ const xLabelsAll = useMemo(() => data.map((d) => fmtAxisDate(getX(d))), [data, getX]);
130
+ const margin = useMemo(
131
+ () => autoMargin({ left: [...topLabels, ...bottomLabels], bottom: xLabelsAll }),
132
+ [topLabels, bottomLabels, xLabelsAll]
133
+ );
134
+ const xMax = Math.max(plot.width - margin.left - margin.right, 0);
135
+ const plotH = plot.height - margin.top - margin.bottom - PANE_GAP;
136
+ const topH = Math.max(Math.round(plotH * topFraction), 1);
137
+ const bottomH = Math.max(plotH - topH, 1);
138
+ const bottomTop = topH + PANE_GAP;
139
+ const innerH = topH + PANE_GAP + bottomH;
140
+ const xScale = useMemo(
141
+ () => scalePoint({ domain: data.map(getX), range: [0, xMax], padding: 0.3 }),
142
+ [data, xMax, getX]
143
+ );
144
+ const topYScale = useMemo(
145
+ () => scaleLinear({
146
+ domain: topDomain,
147
+ range: [topH, 0],
148
+ ...useNiceTop && { nice: true }
149
+ }),
150
+ [topDomain, useNiceTop, topH]
151
+ );
152
+ const bottomYScale = useMemo(
153
+ () => scaleLinear({
154
+ domain: bottomDomain,
119
155
  range: [bottomH, 0],
120
- nice: true
121
- });
122
- }, [data, getBar, bottomH]);
123
- const tooltipStyles = useTooltipStyles();
124
- const { tip, tooltipRef, syncedPoint, isDirectHover, handleMouse, handleLeave } = useHoverSync(
125
- {
126
- data,
127
- chartId,
128
- getKey: getX,
129
- xScale,
130
- marginLeft: MARGIN.left
131
- }
156
+ ...useNiceBottom && { nice: true }
157
+ }),
158
+ [bottomDomain, bottomH, useNiceBottom]
132
159
  );
160
+ const cursor = useChartCursor({
161
+ data,
162
+ chartId,
163
+ getKey: getX,
164
+ xScale,
165
+ marginLeft: margin.left
166
+ });
133
167
  const tickValues = useMemo(() => smartTicks(data.map(getX), xMax), [data, xMax, getX]);
134
168
  const barWidth = data.length > 0 ? Math.max(xMax / data.length * 0.6, 2) : 2;
169
+ const histogramBars = useMemo(() => {
170
+ if (!barVisible) return [];
171
+ const y0 = bottomYScale(0);
172
+ const bars = [];
173
+ for (const d of data) {
174
+ const v = getBar(d);
175
+ if (v === null || v === void 0 || Number.isNaN(v)) continue;
176
+ const cx = xScale(getX(d)) ?? 0;
177
+ const yVal = bottomYScale(v);
178
+ bars.push({
179
+ key: `bar-${getX(d)}`,
180
+ x: cx - barWidth / 2,
181
+ y: Math.min(y0, yVal),
182
+ width: barWidth,
183
+ height: Math.max(Math.abs(yVal - y0), 1),
184
+ fill: v >= 0 ? barColorPositive : barColorNegative
185
+ });
186
+ }
187
+ return bars;
188
+ }, [
189
+ barVisible,
190
+ data,
191
+ getBar,
192
+ getX,
193
+ xScale,
194
+ bottomYScale,
195
+ barWidth,
196
+ barColorPositive,
197
+ barColorNegative
198
+ ]);
135
199
  const fillPts = useMemo(() => {
136
200
  if (!fillBetween) return [];
137
- const fromLine = series.find((s) => s.key === fillBetween.from);
138
- const toLine = series.find((s) => s.key === fillBetween.to);
201
+ const fromLine = visibleSeries.find((s) => s.key === fillBetween.from);
202
+ const toLine = visibleSeries.find((s) => s.key === fillBetween.to);
139
203
  if (!fromLine || !toLine) return [];
140
204
  const out = [];
141
205
  for (const d of data) {
@@ -146,10 +210,10 @@ function DualPanelPlot(props) {
146
210
  out.push({ __d: d, __from: f, __to: t });
147
211
  }
148
212
  return out;
149
- }, [data, fillBetween, series]);
213
+ }, [data, fillBetween, visibleSeries]);
150
214
  const lineValid = useMemo(() => {
151
215
  const out = /* @__PURE__ */ new Map();
152
- for (const s of series) {
216
+ for (const s of visibleSeries) {
153
217
  const pts = [];
154
218
  for (const d of data) {
155
219
  const v = s.getValue(d);
@@ -158,12 +222,43 @@ function DualPanelPlot(props) {
158
222
  out.set(s.key, pts);
159
223
  }
160
224
  return out;
161
- }, [data, series]);
162
- const sx = syncedPoint ? xScale(getX(syncedPoint)) ?? 0 : 0;
163
- const syncedBar = syncedPoint ? getBar(syncedPoint) : null;
225
+ }, [data, visibleSeries]);
226
+ const markerNodes = useMemo(
227
+ () => visibleSeries.flatMap((s) => {
228
+ const getMarker = s.getMarker;
229
+ if (!getMarker) return [];
230
+ const pts = lineValid.get(s.key) ?? [];
231
+ const markers = [];
232
+ for (const p of pts) {
233
+ const m = getMarker(p.__d);
234
+ if (m === null) continue;
235
+ const cx = xScale(getX(p.__d)) ?? 0;
236
+ const cy = topYScale(p.__y);
237
+ markers.push(
238
+ /* @__PURE__ */ jsx(
239
+ "circle",
240
+ {
241
+ cx,
242
+ cy,
243
+ r: m.r ?? VX.dotR,
244
+ fill: m.color ?? s.color,
245
+ stroke: VX.dotStroke,
246
+ strokeWidth: 2
247
+ },
248
+ `mk-${s.key}-${getX(p.__d)}`
249
+ )
250
+ );
251
+ }
252
+ return markers;
253
+ }),
254
+ [visibleSeries, lineValid, xScale, topYScale, getX]
255
+ );
256
+ const point = cursor.point;
257
+ const sx = point !== null ? xScale(getX(point)) ?? 0 : 0;
258
+ const syncedBar = point !== null ? getBar(point) : null;
164
259
  return /* @__PURE__ */ jsxs(Fragment, { children: [
165
260
  /* @__PURE__ */ jsxs("svg", { width: plot.width, height: plot.height, children: [
166
- /* @__PURE__ */ jsxs(Group, { left: MARGIN.left, top: MARGIN.top, children: [
261
+ /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top, children: [
167
262
  /* @__PURE__ */ jsx(GridRows, { scale: topYScale, width: xMax, stroke: VX.grid, numTicks: 4 }),
168
263
  /* @__PURE__ */ jsx(ZoneRects, { zones: topZones, width: xMax, leftScale: topYScale }),
169
264
  fillBetween && fillPts.length > 0 && /* @__PURE__ */ jsx(
@@ -193,7 +288,7 @@ function DualPanelPlot(props) {
193
288
  },
194
289
  `top-ref-${i}`
195
290
  )),
196
- series.map((s) => {
291
+ visibleSeries.map((s) => {
197
292
  const valid = lineValid.get(s.key) ?? [];
198
293
  if (valid.length === 0) return null;
199
294
  return /* @__PURE__ */ jsx(
@@ -205,13 +300,15 @@ function DualPanelPlot(props) {
205
300
  stroke: s.color,
206
301
  strokeWidth: s.strokeWidth ?? VX.lineWidth,
207
302
  strokeDasharray: s.dash === "dashed" ? VX.dashArray : void 0,
303
+ strokeOpacity: s.strokeOpacity ?? 1,
208
304
  curve: curveMonotoneX
209
305
  },
210
306
  `top-line-${s.key}`
211
307
  );
212
308
  }),
213
- syncedPoint && /* @__PURE__ */ jsx(Fragment, { children: series.map((s) => {
214
- const v = s.getValue(syncedPoint);
309
+ markerNodes,
310
+ point !== null && /* @__PURE__ */ jsx(Fragment, { children: visibleSeries.map((s) => {
311
+ const v = s.getValue(point);
215
312
  if (v === null || v === void 0 || Number.isNaN(v)) return null;
216
313
  return /* @__PURE__ */ jsx(SeriesDot, { cx: sx, cy: topYScale(v), color: s.color }, `top-dot-${s.key}`);
217
314
  }) }),
@@ -221,12 +318,14 @@ function DualPanelPlot(props) {
221
318
  {
222
319
  width: xMax,
223
320
  height: topH + PANE_GAP,
224
- onMove: handleMouse,
225
- onLeave: handleLeave
321
+ onMove: cursor.onPointerMove,
322
+ onLeave: cursor.onPointerLeave,
323
+ onKeyDown: cursor.onKeyDown,
324
+ onBlur: cursor.onBlur
226
325
  }
227
326
  )
228
327
  ] }),
229
- /* @__PURE__ */ jsxs(Group, { left: MARGIN.left, top: MARGIN.top + bottomTop, children: [
328
+ /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top + bottomTop, children: [
230
329
  /* @__PURE__ */ jsx(
231
330
  "line",
232
331
  {
@@ -238,61 +337,54 @@ function DualPanelPlot(props) {
238
337
  strokeWidth: 1
239
338
  }
240
339
  ),
241
- data.map((d) => {
242
- const v = getBar(d);
243
- if (v === null || v === void 0 || Number.isNaN(v)) return null;
244
- const cx = xScale(getX(d)) ?? 0;
245
- const y0 = bottomYScale(0);
246
- const yVal = bottomYScale(v);
247
- return /* @__PURE__ */ jsx(
248
- Bar,
249
- {
250
- x: cx - barWidth / 2,
251
- y: Math.min(y0, yVal),
252
- width: barWidth,
253
- height: Math.max(Math.abs(yVal - y0), 1),
254
- fill: v >= 0 ? barColorPositive : barColorNegative,
255
- fillOpacity: 0.7,
256
- rx: 1.4
257
- },
258
- `bar-${getX(d)}`
259
- );
260
- }),
261
- syncedPoint && /* @__PURE__ */ jsx(Fragment, { children: syncedBar !== null && syncedBar !== void 0 && !Number.isNaN(syncedBar) && /* @__PURE__ */ jsx(
340
+ histogramBars.map((b) => /* @__PURE__ */ jsx(
341
+ Bar,
342
+ {
343
+ x: b.x,
344
+ y: b.y,
345
+ width: b.width,
346
+ height: b.height,
347
+ fill: b.fill,
348
+ fillOpacity: 0.7,
349
+ rx: 1.4
350
+ },
351
+ b.key
352
+ )),
353
+ barVisible && point !== null && syncedBar !== null && syncedBar !== void 0 && !Number.isNaN(syncedBar) && /* @__PURE__ */ jsx(
262
354
  SeriesDot,
263
355
  {
264
356
  cx: sx,
265
357
  cy: bottomYScale(syncedBar),
266
358
  color: syncedBar >= 0 ? barColorPositive : barColorNegative
267
359
  }
268
- ) }),
360
+ ),
269
361
  /* @__PURE__ */ jsx(AxisLeftNumeric, { scale: bottomYScale, numTicks: 3, tickFormat: formatBottom }),
270
362
  /* @__PURE__ */ jsx(AxisBottomDate, { top: bottomH, scale: xScale, tickValues }),
271
363
  /* @__PURE__ */ jsx(
272
364
  HoverOverlay,
273
365
  {
274
366
  width: xMax,
275
- height: bottomH + MARGIN.bottom,
276
- onMove: handleMouse,
277
- onLeave: handleLeave
367
+ height: bottomH + margin.bottom,
368
+ onMove: cursor.onPointerMove,
369
+ onLeave: cursor.onPointerLeave
278
370
  }
279
371
  )
280
372
  ] }),
281
- syncedPoint && /* @__PURE__ */ jsx(Group, { left: MARGIN.left, top: MARGIN.top, children: /* @__PURE__ */ jsx(Crosshair, { x: sx, top: 0, bottom: innerH }) })
373
+ point !== null && /* @__PURE__ */ jsx(Group, { left: margin.left, top: margin.top, children: /* @__PURE__ */ jsx(Crosshair, { x: sx, top: 0, bottom: innerH }) })
282
374
  ] }),
283
- /* @__PURE__ */ jsx(ChartTooltip, { tip: isDirectHover ? tip : null, tooltipRef, styles: tooltipStyles, children: tip && isDirectHover && /* @__PURE__ */ jsxs(Fragment, { children: [
375
+ cursor.isSource && point !== null && /* @__PURE__ */ jsxs(ChartTooltipFloat, { anchor: cursor.anchor, children: [
284
376
  /* @__PURE__ */ jsx(
285
377
  TooltipHeader,
286
378
  {
287
- date: getX(tip.data),
379
+ date: getX(point),
288
380
  ...(() => {
289
- const lbl = tooltipLabel?.(tip.data) ?? null;
381
+ const lbl = tooltipLabel?.(point) ?? null;
290
382
  return lbl !== null ? { label: lbl.text, labelColor: lbl.color } : {};
291
383
  })()
292
384
  }
293
385
  ),
294
386
  /* @__PURE__ */ jsxs(TooltipBody, { children: [
295
- deriveTooltipRows(series, tip.data, formatTop).map((row) => /* @__PURE__ */ jsx(
387
+ deriveTooltipRows(visibleSeries, point, formatTop).map((row) => /* @__PURE__ */ jsx(
296
388
  TooltipRow,
297
389
  {
298
390
  color: row.color,
@@ -304,21 +396,22 @@ function DualPanelPlot(props) {
304
396
  },
305
397
  row.key
306
398
  )),
307
- (() => {
308
- const v = getBar(tip.data);
399
+ barVisible && (() => {
400
+ const v = getBar(point);
309
401
  if (v === null || v === void 0 || Number.isNaN(v)) return null;
402
+ const value = formatBar !== void 0 ? formatBar(v, point) : formatBottom(v);
310
403
  return /* @__PURE__ */ jsx(
311
404
  TooltipRow,
312
405
  {
313
406
  color: v >= 0 ? barColorPositive : barColorNegative,
314
407
  label: barLabel,
315
- value: formatBottom(v),
408
+ value,
316
409
  shape: "bar"
317
410
  }
318
411
  );
319
412
  })()
320
413
  ] })
321
- ] }) })
414
+ ] })
322
415
  ] });
323
416
  }
324
417
  const DualPanel = memo(DualPanelInner);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=DualPanel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DualPanel.test.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/DualPanel.test.tsx"],"names":[],"mappings":""}
@@ -7,8 +7,12 @@ type HeatmapCell = {
7
7
  };
8
8
  export type HeatmapProps<T> = {
9
9
  data: T[];
10
- width: number;
11
- height: number;
10
+ /** Fixed height in pixels. Used when neither `aspectRatio` nor `fill` is set. Default 240. */
11
+ height?: number;
12
+ /** height = Math.round(containerWidth / aspectRatio). Ignored when `fill` is set. */
13
+ aspectRatio?: number;
14
+ /** Fill the parent flex/grid cell's measured height instead of a fixed/derived one. */
15
+ fill?: boolean;
12
16
  chartId: string;
13
17
  /** Extracts the y-axis category (row) from a data point. */
14
18
  getRow: (d: T) => string;
@@ -41,21 +45,21 @@ export type HeatmapProps<T> = {
41
45
  min: string;
42
46
  max: string;
43
47
  };
44
- /**
45
- * The query behind this chart hasn't resolved yet. Renders `ChartPending` (see its JSDoc for the
46
- * three-state rationale) over the full `width` × `height` box in place of the grid, suppressing
47
- * the legend strip and every cell/label/tooltip along with it. Unlike the other six kinds,
48
- * `Heatmap` doesn't compose `ChartFrame` (it takes `width`/`height` directly rather than
49
- * measuring), so this is handled locally instead of forwarded.
50
- */
48
+ /** Accessible text alternative, forwarded to `ChartFrame` as `aria-label` (+ `role="img"`). */
49
+ ariaLabel?: string;
50
+ /** Forwarded to `ChartFrame` — see `ChartPending`'s JSDoc for the three-state rationale. */
51
51
  isPending?: boolean;
52
52
  };
53
53
  /**
54
54
  * Category × category intensity grid. Each cell is a rounded rect filled with the base
55
55
  * color at an opacity derived from its value; empty cells stay a faint neutral track.
56
56
  * Generalizes argo's day-of-week × hour-of-day heatmap. Categorical axes are rendered as
57
- * plain themed `<text>` (cells are not date-categorical, so no useHoverSync / shared
58
- * cursor) — per-cell hover drives the local tooltip directly.
57
+ * plain themed `<text>` (cells are not date-categorical, so there's no shared cursor here) —
58
+ * per-cell hover drives the local tooltip directly.
59
+ *
60
+ * Composes `ChartFrame` purely for measuring (`height`/`aspectRatio`/`fill`, the same three
61
+ * sizing modes every other kind exposes) — `legend={false}` and an empty `series` opt out of
62
+ * `ChartFrame`'s own derived legend, since Heatmap already ships its own gradient strip.
59
63
  */
60
64
  declare function HeatmapInner<T>(props: HeatmapProps<T>): import("react").JSX.Element;
61
65
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Heatmap.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Heatmap.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAatC,kFAAkF;AAClF,KAAK,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,+DAA+D;IAC/D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,yCAAyC;IACzC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAC1B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClD,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uCAAuC;IACvC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,iEAAiE;IACjE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAA;IAChD,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAgCD;;;;;;GAMG;AACH,iBAAS,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,+BAwK9C;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAyB,OAAO,YAAY,CAAA"}
1
+ {"version":3,"file":"Heatmap.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Heatmap.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAWpD,kFAAkF;AAClF,KAAK,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAK9D,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,+DAA+D;IAC/D,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,yCAAyC;IACzC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAC1B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClD,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uCAAuC;IACvC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,iEAAiE;IACjE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAA;IAChD,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAgCD;;;;;;;;;;GAUG;AACH,iBAAS,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,+BAiB9C;AA6KD;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAyB,OAAO,YAAY,CAAA"}