basalt-ui 1.21.0 → 1.23.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 (85) hide show
  1. package/AGENTS.md +11 -1
  2. package/CHANGELOG.md +33 -0
  3. package/MIGRATING.md +205 -9
  4. package/README.md +63 -16
  5. package/agent/rules/basalt-app.md +39 -9
  6. package/agent/rules/basalt-charts.md +41 -6
  7. package/agent/rules/basalt-router.md +1 -1
  8. package/agent/rules/basalt-state.md +4 -4
  9. package/agent/rules/basalt-tokens.md +25 -4
  10. package/agent/skills/basalt-app/SKILL.md +4 -3
  11. package/agent/skills/basalt-charts/SKILL.md +23 -8
  12. package/agent/templates/DESIGN.md.tpl +3 -1
  13. package/configs/oxlint-plugin.js +86 -9
  14. package/configs/oxlint-plugin.test.ts +173 -0
  15. package/dist/charts/hooks/useBandPlot.d.ts +138 -0
  16. package/dist/charts/hooks/useBandPlot.d.ts.map +1 -0
  17. package/dist/charts/hooks/useBandPlot.js +127 -0
  18. package/dist/charts/index.d.ts +4 -0
  19. package/dist/charts/index.d.ts.map +1 -1
  20. package/dist/charts/index.js +14 -0
  21. package/dist/charts/kinds/BandStrip.d.ts +113 -0
  22. package/dist/charts/kinds/BandStrip.d.ts.map +1 -0
  23. package/dist/charts/kinds/BandStrip.js +218 -0
  24. package/dist/charts/kinds/BandStrip.test.d.ts +2 -0
  25. package/dist/charts/kinds/BandStrip.test.d.ts.map +1 -0
  26. package/dist/charts/kinds/Bars.d.ts +5 -1
  27. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  28. package/dist/charts/kinds/Bars.js +2 -0
  29. package/dist/charts/kinds/MirroredBars.d.ts +93 -0
  30. package/dist/charts/kinds/MirroredBars.d.ts.map +1 -0
  31. package/dist/charts/kinds/MirroredBars.js +315 -0
  32. package/dist/charts/kinds/MirroredBars.test.d.ts +2 -0
  33. package/dist/charts/kinds/MirroredBars.test.d.ts.map +1 -0
  34. package/dist/charts/kinds/MultiLine.d.ts +5 -1
  35. package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
  36. package/dist/charts/kinds/MultiLine.js +2 -0
  37. package/dist/charts/kinds/StackedArea.d.ts +5 -1
  38. package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
  39. package/dist/charts/kinds/StackedArea.js +2 -0
  40. package/dist/charts/kinds/ZonedLine.d.ts +5 -1
  41. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  42. package/dist/charts/kinds/ZonedLine.js +2 -0
  43. package/dist/charts/primitives/CartesianChart.d.ts +18 -2
  44. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
  45. package/dist/charts/primitives/CartesianChart.js +5 -2
  46. package/dist/charts/primitives/HatchPattern.d.ts +31 -0
  47. package/dist/charts/primitives/HatchPattern.d.ts.map +1 -0
  48. package/dist/charts/primitives/HatchPattern.js +31 -0
  49. package/dist/cli/index.d.ts +9 -1
  50. package/dist/cli/index.d.ts.map +1 -1
  51. package/dist/cli/index.js +275 -48
  52. package/dist/cli/shipped-versions.test.d.ts +2 -0
  53. package/dist/cli/shipped-versions.test.d.ts.map +1 -0
  54. package/dist/guard/index.d.ts +67 -0
  55. package/dist/guard/index.d.ts.map +1 -1
  56. package/dist/guard/index.js +70 -11
  57. package/dist/vite.d.ts +44 -2
  58. package/dist/vite.d.ts.map +1 -1
  59. package/dist/vite.js +71 -26
  60. package/llms.txt +2 -2
  61. package/package.json +1 -1
  62. package/src/charts/hooks/useBandPlot.ts +302 -0
  63. package/src/charts/index.ts +14 -0
  64. package/src/charts/kinds/BandStrip.test.tsx +200 -0
  65. package/src/charts/kinds/BandStrip.tsx +364 -0
  66. package/src/charts/kinds/Bars.tsx +7 -1
  67. package/src/charts/kinds/DualPanel.test.tsx +10 -4
  68. package/src/charts/kinds/MirroredBars.test.tsx +193 -0
  69. package/src/charts/kinds/MirroredBars.tsx +455 -0
  70. package/src/charts/kinds/MultiLine.tsx +7 -1
  71. package/src/charts/kinds/StackedArea.tsx +7 -1
  72. package/src/charts/kinds/ZonedLine.tsx +7 -1
  73. package/src/charts/primitives/CartesianChart.test.tsx +86 -4
  74. package/src/charts/primitives/CartesianChart.tsx +28 -3
  75. package/src/charts/primitives/HatchPattern.tsx +55 -0
  76. package/src/cli/check-theme.test.ts +35 -0
  77. package/src/cli/help.test.ts +5 -1
  78. package/src/cli/index.ts +552 -79
  79. package/src/cli/shipped-versions.test.ts +83 -0
  80. package/src/cli/toolchain-wiring.test.ts +362 -6
  81. package/src/cli/waiver-audit.test.ts +88 -4
  82. package/src/guard/check-source.test.ts +293 -0
  83. package/src/guard/index.ts +209 -20
  84. package/src/vite.test.ts +112 -0
  85. package/src/vite.ts +147 -31
@@ -0,0 +1,218 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { Group } from "@visx/group";
3
+ import { memo, useMemo } from "react";
4
+ import { VX, alpha } from "../../tokens/index.js";
5
+ import { useBandPlot } from "../hooks/useBandPlot.js";
6
+ import { AxisBottomDate } from "../primitives/Axes.js";
7
+ import { ChartFrame, resolveLegend } from "../primitives/ChartFrame.js";
8
+ import {
9
+ ChartTooltipFloat,
10
+ TooltipBody,
11
+ TooltipHeader,
12
+ TooltipRow
13
+ } from "../primitives/ChartTooltip.js";
14
+ import { Crosshair } from "../primitives/Crosshair.js";
15
+ import { HatchPattern, hatchFill, hatchSizeFor } from "../primitives/HatchPattern.js";
16
+ import { HoverOverlay } from "../primitives/HoverOverlay.js";
17
+ import { fmtAxisDate } from "../utils/format.js";
18
+ const DEFAULT_MARKER_INSET = 6;
19
+ function BandStripInner(props) {
20
+ const { series, chartId, height, fill, legend, ariaLabel, isPending } = props;
21
+ return /* @__PURE__ */ jsx(
22
+ ChartFrame,
23
+ {
24
+ series,
25
+ chartId,
26
+ ...height !== void 0 && { height },
27
+ ...fill !== void 0 && { fill },
28
+ ...ariaLabel !== void 0 && { ariaLabel },
29
+ ...isPending !== void 0 && { isPending },
30
+ legend: resolveLegend(legend),
31
+ children: (plot) => /* @__PURE__ */ jsx(BandStripPlot, { ...props, plot })
32
+ }
33
+ );
34
+ }
35
+ function BandStripPlot(props) {
36
+ const {
37
+ data,
38
+ chartId,
39
+ getX,
40
+ series,
41
+ getBand,
42
+ formatX = fmtAxisDate,
43
+ xTickValues,
44
+ fold,
45
+ cursorResolution = "leading",
46
+ tooltip,
47
+ absentState,
48
+ margin: marginOverride,
49
+ ariaLabel,
50
+ plot
51
+ } = props;
52
+ const { hidden } = plot;
53
+ const styleByKey = useMemo(() => new Map(series.map((s) => [s.key, s])), [series]);
54
+ const band = useBandPlot({
55
+ data,
56
+ chartId,
57
+ getX,
58
+ formatX,
59
+ width: plot.width,
60
+ cursorResolution,
61
+ ...fold !== void 0 && { fold },
62
+ ...xTickValues !== void 0 && { xTickValues },
63
+ ...marginOverride !== void 0 && { margin: marginOverride },
64
+ ...tooltip !== void 0 && { tooltip }
65
+ });
66
+ const { bands, margin, plotWidth, scale, cursor, point, crosshairX, step, bandWidth } = band;
67
+ const stripHeight = Math.max(plot.height - margin.top - margin.bottom, 1);
68
+ const hatchId = `${chartId}-band-absent`;
69
+ const absentColor = (absentState === void 0 ? void 0 : styleByKey.get(absentState)?.color) ?? VX.neutral;
70
+ const rects = useMemo(() => {
71
+ const out = [];
72
+ bands.forEach((d, i) => {
73
+ const span = getBand(d);
74
+ const style = styleByKey.get(span.state);
75
+ if (style === void 0 || hidden.has(span.state)) return;
76
+ const absent = clampFraction(span.absentFraction);
77
+ const measuredWidth = bandWidth * (1 - absent);
78
+ const hatchWidth = bandWidth - measuredWidth;
79
+ const x = i * step;
80
+ const markerKey = span.marker?.state ?? span.state;
81
+ const markerColor = styleByKey.get(markerKey)?.color;
82
+ const inset = span.marker?.inset ?? DEFAULT_MARKER_INSET;
83
+ out.push(
84
+ /* @__PURE__ */ jsxs("g", { children: [
85
+ measuredWidth > 0 && /* @__PURE__ */ jsx(
86
+ "rect",
87
+ {
88
+ x,
89
+ y: 0,
90
+ width: measuredWidth,
91
+ height: stripHeight,
92
+ rx: 1,
93
+ fill: span.fill ?? alpha(style.color, style.fillOpacity ?? 1),
94
+ pointerEvents: "none"
95
+ }
96
+ ),
97
+ hatchWidth > 0 && /* @__PURE__ */ jsx(
98
+ "rect",
99
+ {
100
+ x: x + measuredWidth,
101
+ y: 0,
102
+ width: hatchWidth,
103
+ height: stripHeight,
104
+ rx: 1,
105
+ fill: hatchFill(hatchId),
106
+ pointerEvents: "none"
107
+ }
108
+ ),
109
+ span.marker !== void 0 && markerColor !== void 0 && measuredWidth > 0 && /* @__PURE__ */ jsx(
110
+ "rect",
111
+ {
112
+ x,
113
+ y: inset,
114
+ width: measuredWidth,
115
+ height: Math.max(stripHeight - 2 * inset, 2),
116
+ rx: 1,
117
+ fill: markerColor,
118
+ pointerEvents: "none"
119
+ }
120
+ )
121
+ ] }, getX(d))
122
+ );
123
+ });
124
+ return out;
125
+ }, [bands, getBand, getX, styleByKey, hidden, bandWidth, step, stripHeight, hatchId]);
126
+ if (plotWidth <= 0 || bands.length === 0) return null;
127
+ const cfg = tooltip === false ? void 0 : tooltip;
128
+ const badge = cfg?.label === void 0 || point === null ? null : cfg.label(point);
129
+ const row = point === null ? null : deriveBandRow(getBand(point), styleByKey, hidden, point);
130
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
131
+ /* @__PURE__ */ jsxs("svg", { ref: band.svgRef, width: plot.width, height: plot.height, children: [
132
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
133
+ HatchPattern,
134
+ {
135
+ id: hatchId,
136
+ color: absentColor,
137
+ opacity: 0.7,
138
+ size: hatchSizeFor(bandWidth)
139
+ }
140
+ ) }),
141
+ /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top, children: [
142
+ rects,
143
+ crosshairX !== null && /* @__PURE__ */ jsx(Crosshair, { x: crosshairX, top: 0, bottom: stripHeight }),
144
+ /* @__PURE__ */ jsx(
145
+ AxisBottomDate,
146
+ {
147
+ top: stripHeight,
148
+ scale,
149
+ tickValues: band.tickValues,
150
+ tickFormat: (v) => formatX(String(v))
151
+ }
152
+ ),
153
+ /* @__PURE__ */ jsx(
154
+ HoverOverlay,
155
+ {
156
+ width: plotWidth,
157
+ height: stripHeight,
158
+ onMove: cursor.onPointerMove,
159
+ onLeave: cursor.onPointerLeave,
160
+ onKeyDown: cursor.onKeyDown,
161
+ onBlur: cursor.onBlur,
162
+ valueMax: Math.max(bands.length - 1, 0),
163
+ ...point !== null && {
164
+ valueNow: bands.indexOf(point),
165
+ valueText: formatX(getX(point))
166
+ },
167
+ ...ariaLabel !== void 0 && { ariaLabel }
168
+ }
169
+ )
170
+ ] })
171
+ ] }),
172
+ band.showTooltip && point !== null && /* @__PURE__ */ jsxs(ChartTooltipFloat, { anchor: band.tooltipAnchor, ariaLive: band.ariaLive, children: [
173
+ /* @__PURE__ */ jsx(
174
+ TooltipHeader,
175
+ {
176
+ date: getX(point),
177
+ ...cfg?.formatHeader !== void 0 && {
178
+ format: (key) => cfg.formatHeader?.(key, point) ?? key
179
+ },
180
+ ...badge !== null && { label: badge.text, labelColor: badge.color }
181
+ }
182
+ ),
183
+ /* @__PURE__ */ jsxs(TooltipBody, { children: [
184
+ cfg?.prependRows?.(point, { hidden }),
185
+ row !== null && /* @__PURE__ */ jsx(
186
+ TooltipRow,
187
+ {
188
+ color: row.color,
189
+ label: row.label,
190
+ value: row.value,
191
+ shape: row.shape,
192
+ dashed: row.dashed
193
+ }
194
+ ),
195
+ cfg?.extraRows?.(point, { hidden })
196
+ ] })
197
+ ] })
198
+ ] });
199
+ }
200
+ function clampFraction(value) {
201
+ if (value === void 0 || !Number.isFinite(value)) return 0;
202
+ return Math.min(Math.max(value, 0), 1);
203
+ }
204
+ function deriveBandRow(span, styleByKey, hidden, datum) {
205
+ const style = styleByKey.get(span.state);
206
+ if (style === void 0 || style.tooltip === false || hidden.has(span.state)) return null;
207
+ return {
208
+ color: style.color,
209
+ label: style.label,
210
+ value: style.formatValue?.(datum) ?? "",
211
+ shape: style.mark === "line" ? "line" : "bar",
212
+ dashed: style.dash === "dashed"
213
+ };
214
+ }
215
+ const BandStrip = memo(BandStripInner);
216
+ export {
217
+ BandStrip
218
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=BandStrip.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BandStrip.test.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/BandStrip.test.tsx"],"names":[],"mappings":""}
@@ -87,8 +87,12 @@ export type BarsProps<T> = {
87
87
  barLayout?: 'stacked' | 'grouped';
88
88
  /** Per-bar opacity override. Receives the data point + bar key. Default 0.85. */
89
89
  barOpacity?: (d: T, key: string) => number;
90
- /** X tick count override. Default: as many as fit. */
90
+ /** Exact number of x ticks. Default: as many as fit. Ignored when `xTickValues` is set. */
91
91
  xTicks?: number;
92
+ /** Which domain keys get a tick, from the full key list and the resolved plot width. Takes
93
+ * precedence over `xTicks` — see `CartesianChartProps.xTickValues` for why a count is not
94
+ * always enough. */
95
+ xTickValues?: (keys: readonly string[], xMax: number) => readonly string[];
92
96
  /** X tick label formatter. Default `fmtAxisDate` (DD.MM). */
93
97
  formatX?: (key: string) => string;
94
98
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Bars.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Bars.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Bars.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/Bars.tsx"],"names":[],"mappings":"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"}
@@ -24,6 +24,7 @@ function BarsInner(props) {
24
24
  barLayout = "stacked",
25
25
  barOpacity,
26
26
  xTicks,
27
+ xTickValues,
27
28
  formatX,
28
29
  cursorResolution,
29
30
  tooltip,
@@ -128,6 +129,7 @@ function BarsInner(props) {
128
129
  y: yConfig,
129
130
  ...y2 !== void 0 && { y2 },
130
131
  ...xTicks !== void 0 && { xTicks },
132
+ ...xTickValues !== void 0 && { xTickValues },
131
133
  ...formatX !== void 0 && { formatX },
132
134
  ...cursorResolution !== void 0 && { cursorResolution },
133
135
  ...zones !== void 0 && { zones },
@@ -0,0 +1,93 @@
1
+ import type { ChartMargin } from '../../tokens/index.js';
2
+ import type { CursorResolution } from '../cursor/resolve.js';
3
+ import type { BandFold, BandTooltipConfig } from '../hooks/useBandPlot.js';
4
+ import type { ChartLegendConfig, ChartSeries } from '../series.js';
5
+ /** One of the two panes. Each resolves its own domain — that is the whole point of the kind. */
6
+ export type MirroredBarPane = {
7
+ /** Key of the `series` entry this pane draws: its colour, its legend entry, its tooltip row. */
8
+ key: string;
9
+ /**
10
+ * The pane's upper bound. `'auto'` (default) is its own visible maximum; a number pins it.
11
+ *
12
+ * A pane has no LOWER bound to configure — a mirrored bar's length is its magnitude measured
13
+ * from the shared baseline, so the pane's zero IS the baseline. That is also why the two panes
14
+ * never share a domain: an upload an order of magnitude below its download flattens to a line
15
+ * along the baseline on a shared scale, and it is the half that explains a stalled call.
16
+ */
17
+ max?: number | 'auto';
18
+ /** When `max` is `'auto'`: floors the upper bound, so a quiet window doesn't amplify noise to
19
+ * full height. */
20
+ autoMaxFloor?: number;
21
+ /** Tick count for this pane's own axis. Default 3. */
22
+ ticks?: number;
23
+ /** Tick + tooltip formatter for this pane. A pane's axis is in its OWN units — one shared
24
+ * formatter would be wrong for at least one of them whenever the two differ. */
25
+ format: (v: number) => string;
26
+ };
27
+ export type MirroredBarsProps<T> = {
28
+ data: readonly T[];
29
+ chartId: string;
30
+ /** Extracts the x-domain key — a slot start, hence the `'leading'` cursor default. */
31
+ getX: (d: T) => string;
32
+ /**
33
+ * The single source of truth for bar colours, legend entries and tooltip rows. `up.key` and
34
+ * `down.key` name two of these; any further entry is legend-only (give it `getValue: () => null`)
35
+ * — which is how ABSENCE gets named, and it has to be: a hatched bar is the one mark on this
36
+ * chart a reader cannot decode from either axis.
37
+ */
38
+ series: readonly ChartSeries<T>[];
39
+ /** The pane drawn ABOVE the baseline. */
40
+ up: MirroredBarPane;
41
+ /** The pane drawn BELOW the baseline. */
42
+ down: MirroredBarPane;
43
+ /** The up pane's share of the bar band. Default 0.35 — the mirrored pair is usually asymmetric,
44
+ * and splitting evenly spends most of the chart on empty space above the smaller half. */
45
+ upFraction?: number;
46
+ /**
47
+ * 0..1 of this bar's width no source sample covers, hatched across the FULL band height.
48
+ *
49
+ * Full height, both panes, deliberately: a hatch drawn on one pane only reads as "that half
50
+ * measured zero", which is the measured-and-idle state absence must stay distinguishable from.
51
+ */
52
+ getAbsentFraction?: (d: T) => number;
53
+ /** Per-datum bar opacity — a real but qualified measurement (a short bucket, a partial interval)
54
+ * drawn dimmer. Default 1. */
55
+ getBarOpacity?: (d: T) => number;
56
+ /** Fixed height in px, forwarded to `ChartFrame`. Default 240. */
57
+ height?: number;
58
+ fill?: boolean;
59
+ formatX?: (key: string) => string;
60
+ xTickValues?: (keys: readonly string[], plotWidth: number) => readonly string[];
61
+ fold?: BandFold<T>;
62
+ /** Default `'leading'` — see `BandStripProps.cursorResolution`. */
63
+ cursorResolution?: CursorResolution;
64
+ tooltip?: BandTooltipConfig<T> | false;
65
+ legend?: ChartLegendConfig | false;
66
+ /** Series key whose colour the absence hatch is drawn in. Default `VX.neutral`. */
67
+ absentState?: string;
68
+ margin?: Partial<ChartMargin>;
69
+ ariaLabel?: string;
70
+ isPending?: boolean;
71
+ };
72
+ /**
73
+ * Two bar panes over ONE x scale and one cursor, mirrored around a shared baseline, each in its
74
+ * own independent domain.
75
+ *
76
+ * **Why not `DualPanel`.** `DualPanel`'s two panes are a LINE pane and a signed-histogram pane: it
77
+ * requires `series` to be line series it draws with `LinePath`, and its bottom pane takes a single
78
+ * signed `getBar` over one symmetric `[-maxAbs, maxAbs]` scale. Neither half fits. Two independent
79
+ * magnitudes mirrored around a baseline are not one signed quantity — a 220 kB/s down and a 20 kB/s
80
+ * up are two readings, not `+220` and `−20` of one — and forcing them onto one scale is exactly the
81
+ * flattening this shape exists to avoid. Bending `DualPanel` to cover it would mean a
82
+ * `topMark: 'line' | 'bars'` switch, a second value accessor, and a per-pane domain law that
83
+ * contradicts its symmetric one: a fork of its internals wearing one name. It composes the same
84
+ * `useBandPlot` choreography instead, which is where the sharing actually belongs.
85
+ */
86
+ declare function MirroredBarsInner<T>(props: MirroredBarsProps<T>): import("react").JSX.Element;
87
+ /**
88
+ * Hand-memoized: React Compiler does not process the shipped dist, so the hot kind is wrapped in
89
+ * `React.memo` to retain the auto-memoization it had as source (parity with `DualPanel`).
90
+ */
91
+ export declare const MirroredBars: typeof MirroredBarsInner;
92
+ export {};
93
+ //# sourceMappingURL=MirroredBars.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MirroredBars.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/MirroredBars.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAcvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG/D,gGAAgG;AAChG,MAAM,MAAM,eAAe,GAAG;IAC5B,gGAAgG;IAChG,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB;sBACkB;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;oFACgF;IAChF,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IACjC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB;;;;;OAKG;IACH,MAAM,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACjC,yCAAyC;IACzC,EAAE,EAAE,eAAe,CAAA;IACnB,yCAAyC;IACzC,IAAI,EAAE,eAAe,CAAA;IACrB;8FAC0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACpC;kCAC8B;IAC9B,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAChC,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACjC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,CAAA;IAC/E,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;IACtC,MAAM,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAA;IAClC,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAKD;;;;;;;;;;;;;GAaG;AACH,iBAAS,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BAgBxD;AAmUD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAA8B,OAAO,iBAAiB,CAAA"}
@@ -0,0 +1,315 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { Group } from "@visx/group";
3
+ import { scaleLinear } from "@visx/scale";
4
+ import { memo, useMemo } from "react";
5
+ import { VX, alpha } from "../../tokens/index.js";
6
+ import { useBandPlot } from "../hooks/useBandPlot.js";
7
+ import { probeAxisLabels } from "../layout/auto-margin.js";
8
+ import { AxisBottomDate, AxisLeftNumeric } from "../primitives/Axes.js";
9
+ import { ChartFrame, resolveLegend } from "../primitives/ChartFrame.js";
10
+ import {
11
+ ChartTooltipFloat,
12
+ TooltipBody,
13
+ TooltipHeader,
14
+ TooltipRow
15
+ } from "../primitives/ChartTooltip.js";
16
+ import { Crosshair } from "../primitives/Crosshair.js";
17
+ import { HatchPattern, hatchFill, hatchSizeFor } from "../primitives/HatchPattern.js";
18
+ import { HoverOverlay } from "../primitives/HoverOverlay.js";
19
+ import { deriveTooltipRows } from "../series.js";
20
+ import { fmtAxisDate } from "../utils/format.js";
21
+ const DEFAULT_UP_FRACTION = 0.35;
22
+ const DEFAULT_PANE_TICKS = 3;
23
+ function MirroredBarsInner(props) {
24
+ const { series, chartId, height, fill, legend, ariaLabel, isPending } = props;
25
+ return /* @__PURE__ */ jsx(
26
+ ChartFrame,
27
+ {
28
+ series,
29
+ chartId,
30
+ ...height !== void 0 && { height },
31
+ ...fill !== void 0 && { fill },
32
+ ...ariaLabel !== void 0 && { ariaLabel },
33
+ ...isPending !== void 0 && { isPending },
34
+ legend: resolveLegend(legend),
35
+ children: (plot) => /* @__PURE__ */ jsx(MirroredBarsPlot, { ...props, plot })
36
+ }
37
+ );
38
+ }
39
+ function MirroredBarsPlot(props) {
40
+ const {
41
+ data,
42
+ chartId,
43
+ getX,
44
+ series,
45
+ up,
46
+ down,
47
+ upFraction = DEFAULT_UP_FRACTION,
48
+ getAbsentFraction,
49
+ getBarOpacity,
50
+ formatX = fmtAxisDate,
51
+ xTickValues,
52
+ fold,
53
+ cursorResolution = "leading",
54
+ tooltip,
55
+ absentState,
56
+ margin: marginOverride,
57
+ ariaLabel,
58
+ plot
59
+ } = props;
60
+ const { hidden } = plot;
61
+ const seriesByKey = useMemo(() => new Map(series.map((s) => [s.key, s])), [series]);
62
+ const upSeries = seriesByKey.get(up.key);
63
+ const downSeries = seriesByKey.get(down.key);
64
+ const upVisible = upSeries !== void 0 && !hidden.has(up.key);
65
+ const downVisible = downSeries !== void 0 && !hidden.has(down.key);
66
+ const upMax = usePaneMax(data, upSeries, up, upVisible);
67
+ const downMax = usePaneMax(data, downSeries, down, downVisible);
68
+ const upTicks = up.ticks ?? DEFAULT_PANE_TICKS;
69
+ const downTicks = down.ticks ?? DEFAULT_PANE_TICKS;
70
+ const leftLabels = useMemo(() => {
71
+ const labels = [];
72
+ if (upVisible) {
73
+ labels.push(
74
+ ...probeAxisLabels({ domain: [0, upMax], ticks: upTicks, format: up.format }).labels
75
+ );
76
+ }
77
+ if (downVisible) {
78
+ labels.push(
79
+ ...probeAxisLabels({ domain: [0, downMax], ticks: downTicks, format: down.format }).labels
80
+ );
81
+ }
82
+ return labels;
83
+ }, [upVisible, downVisible, upMax, downMax, upTicks, downTicks, up.format, down.format]);
84
+ const band = useBandPlot({
85
+ data,
86
+ chartId,
87
+ getX,
88
+ formatX,
89
+ width: plot.width,
90
+ cursorResolution,
91
+ leftLabels,
92
+ ...fold !== void 0 && { fold },
93
+ ...xTickValues !== void 0 && { xTickValues },
94
+ ...marginOverride !== void 0 && { margin: marginOverride },
95
+ ...tooltip !== void 0 && { tooltip }
96
+ });
97
+ const { bands, margin, plotWidth, scale, cursor, point, crosshairX, step, bandWidth } = band;
98
+ const barBand = Math.max(plot.height - margin.top - margin.bottom, 2);
99
+ const upHeight = Math.max(Math.round(barBand * upFraction), 1);
100
+ const downHeight = Math.max(barBand - upHeight, 1);
101
+ const baseline = upHeight;
102
+ const upScale = useMemo(
103
+ () => scaleLinear({ domain: [0, upMax], range: [0, upHeight] }),
104
+ [upMax, upHeight]
105
+ );
106
+ const downScale = useMemo(
107
+ () => scaleLinear({ domain: [0, downMax], range: [0, downHeight] }),
108
+ [downMax, downHeight]
109
+ );
110
+ const upAxisScale = useMemo(
111
+ () => scaleLinear({ domain: [upMax, 0], range: [0, upHeight] }),
112
+ [upMax, upHeight]
113
+ );
114
+ const hatchId = `${chartId}-mirrored-absent`;
115
+ const absentColor = (absentState === void 0 ? void 0 : seriesByKey.get(absentState)?.color) ?? VX.neutral;
116
+ const drawnUp = upVisible ? upSeries : void 0;
117
+ const drawnDown = downVisible ? downSeries : void 0;
118
+ const bars = useMemo(() => {
119
+ const out = [];
120
+ bands.forEach((d, i) => {
121
+ const x = i * step;
122
+ const absent = clampFraction(getAbsentFraction?.(d));
123
+ const measuredWidth = bandWidth * (1 - absent);
124
+ const hatchWidth = bandWidth - measuredWidth;
125
+ const opacity = getBarOpacity?.(d) ?? 1;
126
+ const upValue = finiteOrNull(drawnUp?.getValue(d));
127
+ const downValue = finiteOrNull(drawnDown?.getValue(d));
128
+ out.push(
129
+ /* @__PURE__ */ jsxs("g", { children: [
130
+ measuredWidth > 0 && drawnUp !== void 0 && upValue !== null && /* @__PURE__ */ jsx(
131
+ "rect",
132
+ {
133
+ x,
134
+ y: baseline - upScale(upValue),
135
+ width: measuredWidth,
136
+ height: Math.max(upScale(upValue), upValue > 0 ? 1 : 0),
137
+ fill: alpha(drawnUp.color, opacity),
138
+ pointerEvents: "none"
139
+ }
140
+ ),
141
+ measuredWidth > 0 && drawnDown !== void 0 && downValue !== null && /* @__PURE__ */ jsx(
142
+ "rect",
143
+ {
144
+ x,
145
+ y: baseline,
146
+ width: measuredWidth,
147
+ height: Math.max(downScale(downValue), downValue > 0 ? 1 : 0),
148
+ fill: alpha(drawnDown.color, opacity),
149
+ pointerEvents: "none"
150
+ }
151
+ ),
152
+ hatchWidth > 0 && /* @__PURE__ */ jsx(
153
+ "rect",
154
+ {
155
+ x: x + measuredWidth,
156
+ y: 0,
157
+ width: hatchWidth,
158
+ height: barBand,
159
+ fill: hatchFill(hatchId),
160
+ pointerEvents: "none"
161
+ }
162
+ )
163
+ ] }, getX(d))
164
+ );
165
+ });
166
+ return out;
167
+ }, [
168
+ bands,
169
+ step,
170
+ bandWidth,
171
+ barBand,
172
+ baseline,
173
+ getX,
174
+ getAbsentFraction,
175
+ getBarOpacity,
176
+ drawnUp,
177
+ drawnDown,
178
+ upScale,
179
+ downScale,
180
+ hatchId
181
+ ]);
182
+ if (plotWidth <= 0 || bands.length === 0) return null;
183
+ const cfg = tooltip === false ? void 0 : tooltip;
184
+ const badge = cfg?.label === void 0 || point === null ? null : cfg.label(point);
185
+ const visibleSeries = series.filter((s) => !hidden.has(s.key)).map((s) => {
186
+ if (s.formatValue !== void 0) return s;
187
+ if (s.key === up.key) return { ...s, formatValue: (v) => up.format(v) };
188
+ if (s.key === down.key) return { ...s, formatValue: (v) => down.format(v) };
189
+ return s;
190
+ });
191
+ const rows = point === null ? [] : deriveTooltipRows(visibleSeries, point, down.format);
192
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
193
+ /* @__PURE__ */ jsxs("svg", { ref: band.svgRef, width: plot.width, height: plot.height, children: [
194
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
195
+ HatchPattern,
196
+ {
197
+ id: hatchId,
198
+ color: absentColor,
199
+ opacity: 0.7,
200
+ size: hatchSizeFor(bandWidth)
201
+ }
202
+ ) }),
203
+ /* @__PURE__ */ jsxs(Group, { left: margin.left, top: margin.top, children: [
204
+ bars,
205
+ upVisible && /* @__PURE__ */ jsx(
206
+ AxisLeftNumeric,
207
+ {
208
+ scale: upAxisScale,
209
+ numTicks: upTicks,
210
+ tickFormat: (v) => up.format(Number(v))
211
+ }
212
+ ),
213
+ downVisible && /* @__PURE__ */ jsx(Group, { top: baseline, children: /* @__PURE__ */ jsx(
214
+ AxisLeftNumeric,
215
+ {
216
+ scale: downScale,
217
+ numTicks: downTicks,
218
+ tickFormat: (v) => down.format(Number(v))
219
+ }
220
+ ) }),
221
+ /* @__PURE__ */ jsx(
222
+ "line",
223
+ {
224
+ x1: 0,
225
+ x2: plotWidth,
226
+ y1: baseline,
227
+ y2: baseline,
228
+ stroke: VX.axisStroke,
229
+ strokeWidth: 1
230
+ }
231
+ ),
232
+ crosshairX !== null && /* @__PURE__ */ jsx(Crosshair, { x: crosshairX, top: 0, bottom: barBand }),
233
+ /* @__PURE__ */ jsx(
234
+ AxisBottomDate,
235
+ {
236
+ top: barBand,
237
+ scale,
238
+ tickValues: band.tickValues,
239
+ tickFormat: (v) => formatX(String(v))
240
+ }
241
+ ),
242
+ /* @__PURE__ */ jsx(
243
+ HoverOverlay,
244
+ {
245
+ width: plotWidth,
246
+ height: barBand,
247
+ onMove: cursor.onPointerMove,
248
+ onLeave: cursor.onPointerLeave,
249
+ onKeyDown: cursor.onKeyDown,
250
+ onBlur: cursor.onBlur,
251
+ valueMax: Math.max(bands.length - 1, 0),
252
+ ...point !== null && {
253
+ valueNow: bands.indexOf(point),
254
+ valueText: formatX(getX(point))
255
+ },
256
+ ...ariaLabel !== void 0 && { ariaLabel }
257
+ }
258
+ )
259
+ ] })
260
+ ] }),
261
+ band.showTooltip && point !== null && /* @__PURE__ */ jsxs(ChartTooltipFloat, { anchor: band.tooltipAnchor, ariaLive: band.ariaLive, children: [
262
+ /* @__PURE__ */ jsx(
263
+ TooltipHeader,
264
+ {
265
+ date: getX(point),
266
+ ...cfg?.formatHeader !== void 0 && {
267
+ format: (key) => cfg.formatHeader?.(key, point) ?? key
268
+ },
269
+ ...badge !== null && { label: badge.text, labelColor: badge.color }
270
+ }
271
+ ),
272
+ /* @__PURE__ */ jsxs(TooltipBody, { children: [
273
+ cfg?.prependRows?.(point, { hidden }),
274
+ rows.map((row) => /* @__PURE__ */ jsx(
275
+ TooltipRow,
276
+ {
277
+ color: row.color,
278
+ label: row.label,
279
+ value: row.value,
280
+ shape: row.shape,
281
+ dashed: row.dashed,
282
+ ...row.strokeWidth !== void 0 && { strokeWidth: row.strokeWidth }
283
+ },
284
+ row.key
285
+ )),
286
+ cfg?.extraRows?.(point, { hidden })
287
+ ] })
288
+ ] })
289
+ ] });
290
+ }
291
+ function clampFraction(value) {
292
+ if (value === void 0 || !Number.isFinite(value)) return 0;
293
+ return Math.min(Math.max(value, 0), 1);
294
+ }
295
+ function finiteOrNull(v) {
296
+ return v === null || v === void 0 || Number.isNaN(v) ? null : v;
297
+ }
298
+ function usePaneMax(data, paneSeries, pane, visible) {
299
+ return useMemo(() => {
300
+ if (pane.max !== void 0 && pane.max !== "auto") return pane.max || 1;
301
+ if (!visible || paneSeries === void 0) return 1;
302
+ let max = 0;
303
+ for (const d of data) {
304
+ const v = paneSeries.getValue(d);
305
+ if (v === null || Number.isNaN(v)) continue;
306
+ if (v > max) max = v;
307
+ }
308
+ const floored = pane.autoMaxFloor === void 0 ? max : Math.max(max, pane.autoMaxFloor);
309
+ return floored || 1;
310
+ }, [data, paneSeries, pane.max, pane.autoMaxFloor, visible]);
311
+ }
312
+ const MirroredBars = memo(MirroredBarsInner);
313
+ export {
314
+ MirroredBars
315
+ };