basalt-ui 1.14.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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +8 -0
- package/README.md +38 -2
- package/agent/rules/basalt-charts.md +260 -108
- package/agent/rules/basalt-mantine.md +4 -2
- package/agent/skills/basalt-charts/SKILL.md +114 -64
- package/agent/skills/basalt-design/SKILL.md +4 -3
- package/configs/oxlint-plugin.js +152 -0
- package/configs/oxlint-plugin.test.ts +107 -0
- package/configs/oxlint.json +2 -0
- package/dist/charts/cursor/resolve.d.ts +33 -0
- package/dist/charts/cursor/resolve.d.ts.map +1 -0
- package/dist/charts/cursor/resolve.js +61 -0
- package/dist/charts/cursor/resolve.test.d.ts +2 -0
- package/dist/charts/cursor/resolve.test.d.ts.map +1 -0
- package/dist/charts/cursor/scope.d.ts +17 -0
- package/dist/charts/cursor/scope.d.ts.map +1 -0
- package/dist/charts/cursor/scope.js +20 -0
- package/dist/charts/cursor/store.d.ts +31 -0
- package/dist/charts/cursor/store.d.ts.map +1 -0
- package/dist/charts/cursor/store.js +25 -0
- package/dist/charts/cursor/store.test.d.ts +2 -0
- package/dist/charts/cursor/store.test.d.ts.map +1 -0
- package/dist/charts/hooks/useChartCursor.d.ts +39 -0
- package/dist/charts/hooks/useChartCursor.d.ts.map +1 -0
- package/dist/charts/hooks/useChartCursor.js +104 -0
- package/dist/charts/hooks/useChartSize.d.ts +8 -4
- package/dist/charts/hooks/useChartSize.d.ts.map +1 -1
- package/dist/charts/index.d.ts +16 -13
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +38 -19
- package/dist/charts/kinds/Bars.d.ts +25 -47
- package/dist/charts/kinds/Bars.d.ts.map +1 -1
- package/dist/charts/kinds/Bars.js +230 -390
- package/dist/charts/kinds/Donut.d.ts +5 -4
- package/dist/charts/kinds/Donut.d.ts.map +1 -1
- package/dist/charts/kinds/Donut.js +17 -14
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +136 -90
- package/dist/charts/kinds/Heatmap.d.ts +15 -11
- package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
- package/dist/charts/kinds/Heatmap.js +38 -22
- package/dist/charts/kinds/MultiLine.d.ts +27 -35
- package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
- package/dist/charts/kinds/MultiLine.js +114 -237
- package/dist/charts/kinds/StackedArea.d.ts +21 -10
- package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
- package/dist/charts/kinds/StackedArea.js +74 -132
- package/dist/charts/kinds/ZonedLine.d.ts +24 -40
- package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
- package/dist/charts/kinds/ZonedLine.js +103 -184
- package/dist/charts/layout/auto-margin.d.ts +60 -0
- package/dist/charts/layout/auto-margin.d.ts.map +1 -0
- package/dist/charts/layout/auto-margin.js +37 -0
- package/dist/charts/layout/auto-margin.test.d.ts +2 -0
- package/dist/charts/layout/auto-margin.test.d.ts.map +1 -0
- package/dist/charts/primitives/CartesianChart.d.ts +143 -0
- package/dist/charts/primitives/CartesianChart.d.ts.map +1 -0
- package/dist/charts/primitives/CartesianChart.js +349 -0
- package/dist/charts/primitives/CartesianChart.test.d.ts +2 -0
- package/dist/charts/primitives/CartesianChart.test.d.ts.map +1 -0
- package/dist/charts/primitives/ChartFrame.d.ts +16 -5
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +17 -2
- package/dist/charts/primitives/ChartLegend.d.ts +12 -1
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +21 -3
- package/dist/charts/primitives/ChartLegend.test.d.ts +2 -0
- package/dist/charts/primitives/ChartLegend.test.d.ts.map +1 -0
- package/dist/charts/primitives/ChartTooltip.d.ts +16 -16
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +45 -19
- package/dist/charts/primitives/HoverOverlay.d.ts +19 -4
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +22 -1
- package/dist/charts/primitives/XZoneRects.d.ts +40 -0
- package/dist/charts/primitives/XZoneRects.d.ts.map +1 -0
- package/dist/charts/primitives/XZoneRects.js +28 -0
- package/dist/charts/primitives/XZoneRects.test.d.ts +2 -0
- package/dist/charts/primitives/XZoneRects.test.d.ts.map +1 -0
- package/dist/charts/series.d.ts +16 -1
- package/dist/charts/series.d.ts.map +1 -1
- package/dist/charts/series.js +3 -1
- package/dist/charts/series.test.d.ts +2 -0
- package/dist/charts/series.test.d.ts.map +1 -0
- package/dist/charts/utils/measure-text.d.ts +25 -0
- package/dist/charts/utils/measure-text.d.ts.map +1 -0
- package/dist/charts/utils/measure-text.js +64 -0
- package/dist/charts/utils/measure-text.test.d.ts +2 -0
- package/dist/charts/utils/measure-text.test.d.ts.map +1 -0
- package/dist/content/fence-block.d.ts.map +1 -1
- package/dist/surfaces.d.ts +1 -1
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +1 -1
- package/dist/tokens/chart-margin.test.d.ts +2 -0
- package/dist/tokens/chart-margin.test.d.ts.map +1 -0
- package/dist/tokens/index.d.ts +29 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +10 -0
- package/dist/tokens/palette.d.ts +4 -0
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +3 -0
- package/llms.txt +3 -3
- package/package.json +1 -1
- package/src/charts/cursor/resolve.test.ts +61 -0
- package/src/charts/cursor/resolve.ts +102 -0
- package/src/charts/cursor/scope.tsx +32 -0
- package/src/charts/cursor/store.test.ts +46 -0
- package/src/charts/cursor/store.ts +53 -0
- package/src/charts/hooks/useChartCursor.ts +163 -0
- package/src/charts/hooks/useChartSize.ts +8 -4
- package/src/charts/index.ts +34 -14
- package/src/charts/kinds/Bars.tsx +327 -460
- package/src/charts/kinds/Donut.tsx +31 -23
- package/src/charts/kinds/DualPanel.tsx +228 -134
- package/src/charts/kinds/Heatmap.tsx +72 -47
- package/src/charts/kinds/MultiLine.tsx +158 -294
- package/src/charts/kinds/StackedArea.tsx +116 -175
- package/src/charts/kinds/ZonedLine.tsx +148 -255
- package/src/charts/layout/auto-margin.test.ts +42 -0
- package/src/charts/layout/auto-margin.ts +110 -0
- package/src/charts/primitives/CartesianChart.test.ts +99 -0
- package/src/charts/primitives/CartesianChart.tsx +566 -0
- package/src/charts/primitives/ChartFrame.test.tsx +33 -0
- package/src/charts/primitives/ChartFrame.tsx +40 -4
- package/src/charts/primitives/ChartLegend.test.tsx +48 -0
- package/src/charts/primitives/ChartLegend.tsx +45 -2
- package/src/charts/primitives/ChartTooltip.tsx +67 -37
- package/src/charts/primitives/HoverOverlay.tsx +39 -3
- package/src/charts/primitives/XZoneRects.test.tsx +63 -0
- package/src/charts/primitives/XZoneRects.tsx +67 -0
- package/src/charts/series.test.ts +61 -0
- package/src/charts/series.ts +18 -1
- package/src/charts/utils/measure-text.test.ts +36 -0
- package/src/charts/utils/measure-text.ts +109 -0
- package/src/content/fence-block.tsx +2 -3
- package/src/surfaces.ts +2 -1
- package/src/theme/spacing.test.ts +2 -0
- package/src/tokens/chart-margin.test.ts +39 -0
- package/src/tokens/density.test.ts +1 -0
- package/src/tokens/index.ts +36 -0
- package/src/tokens/palette.ts +3 -0
- package/dist/charts/hooks/useChartTooltip.d.ts +0 -13
- package/dist/charts/hooks/useChartTooltip.d.ts.map +0 -1
- package/dist/charts/hooks/useChartTooltip.js +0 -26
- package/dist/charts/hooks/useHoverSync.d.ts +0 -46
- package/dist/charts/hooks/useHoverSync.d.ts.map +0 -1
- package/dist/charts/hooks/useHoverSync.js +0 -75
- package/dist/charts/hover-context.d.ts +0 -21
- package/dist/charts/hover-context.d.ts.map +0 -1
- package/dist/charts/hover-context.js +0 -12
- package/dist/charts/hover-sync.d.ts +0 -14
- package/dist/charts/hover-sync.d.ts.map +0 -1
- package/dist/charts/hover-sync.js +0 -17
- package/dist/charts/primitives/ResponsiveChart.d.ts +0 -45
- package/dist/charts/primitives/ResponsiveChart.d.ts.map +0 -1
- package/dist/charts/primitives/ResponsiveChart.js +0 -24
- package/src/charts/hooks/useChartTooltip.ts +0 -31
- package/src/charts/hooks/useHoverSync.ts +0 -152
- package/src/charts/hover-context.ts +0 -28
- package/src/charts/hover-sync.tsx +0 -37
- package/src/charts/primitives/ResponsiveChart.tsx +0 -64
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
import { Group } from '@visx/group'
|
|
2
|
-
import type { ReactNode } from 'react'
|
|
3
|
-
import { memo, useMemo } from 'react'
|
|
2
|
+
import type { PointerEvent, ReactNode } from 'react'
|
|
3
|
+
import { memo, useMemo, useState } from 'react'
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
ChartTooltipFloat,
|
|
6
6
|
TooltipBody,
|
|
7
7
|
TooltipHeader,
|
|
8
8
|
TooltipRow,
|
|
9
|
-
useTooltipStyles,
|
|
10
9
|
} from '../primitives/ChartTooltip'
|
|
11
|
-
import {
|
|
12
|
-
import { useChartTooltip } from '../hooks/useChartTooltip'
|
|
10
|
+
import { ChartFrame } from '../primitives/ChartFrame'
|
|
13
11
|
import { VX, alpha } from '../../tokens'
|
|
14
12
|
|
|
15
13
|
/** A single resolved heatmap cell — the unit the tooltip and hover operate on. */
|
|
16
14
|
type HeatmapCell = { row: string; col: string; value: number }
|
|
17
15
|
|
|
16
|
+
/** A hovered cell plus the viewport anchor `ChartTooltipFloat` positions against. */
|
|
17
|
+
type HeatmapTip = HeatmapCell & { anchor: { x: number; y: number } }
|
|
18
|
+
|
|
18
19
|
export type HeatmapProps<T> = {
|
|
19
20
|
data: T[]
|
|
20
|
-
|
|
21
|
-
height
|
|
21
|
+
/** Fixed height in pixels. Used when neither `aspectRatio` nor `fill` is set. Default 240. */
|
|
22
|
+
height?: number
|
|
23
|
+
/** height = Math.round(containerWidth / aspectRatio). Ignored when `fill` is set. */
|
|
24
|
+
aspectRatio?: number
|
|
25
|
+
/** Fill the parent flex/grid cell's measured height instead of a fixed/derived one. */
|
|
26
|
+
fill?: boolean
|
|
22
27
|
chartId: string
|
|
23
28
|
/** Extracts the y-axis category (row) from a data point. */
|
|
24
29
|
getRow: (d: T) => string
|
|
@@ -48,13 +53,9 @@ export type HeatmapProps<T> = {
|
|
|
48
53
|
renderTooltip?: (cell: HeatmapCell) => ReactNode
|
|
49
54
|
/** Optional gradient legend strip below the grid (faint → solid color). */
|
|
50
55
|
legend?: { min: string; max: string }
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* the legend strip and every cell/label/tooltip along with it. Unlike the other six kinds,
|
|
55
|
-
* `Heatmap` doesn't compose `ChartFrame` (it takes `width`/`height` directly rather than
|
|
56
|
-
* measuring), so this is handled locally instead of forwarded.
|
|
57
|
-
*/
|
|
56
|
+
/** Accessible text alternative, forwarded to `ChartFrame` as `aria-label` (+ `role="img"`). */
|
|
57
|
+
ariaLabel?: string
|
|
58
|
+
/** Forwarded to `ChartFrame` — see `ChartPending`'s JSDoc for the three-state rationale. */
|
|
58
59
|
isPending?: boolean
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -92,14 +93,42 @@ const LEGEND_LABEL_H = 16
|
|
|
92
93
|
* Category × category intensity grid. Each cell is a rounded rect filled with the base
|
|
93
94
|
* color at an opacity derived from its value; empty cells stay a faint neutral track.
|
|
94
95
|
* Generalizes argo's day-of-week × hour-of-day heatmap. Categorical axes are rendered as
|
|
95
|
-
* plain themed `<text>` (cells are not date-categorical, so no
|
|
96
|
-
*
|
|
96
|
+
* plain themed `<text>` (cells are not date-categorical, so there's no shared cursor here) —
|
|
97
|
+
* per-cell hover drives the local tooltip directly.
|
|
98
|
+
*
|
|
99
|
+
* Composes `ChartFrame` purely for measuring (`height`/`aspectRatio`/`fill`, the same three
|
|
100
|
+
* sizing modes every other kind exposes) — `legend={false}` and an empty `series` opt out of
|
|
101
|
+
* `ChartFrame`'s own derived legend, since Heatmap already ships its own gradient strip.
|
|
97
102
|
*/
|
|
98
103
|
function HeatmapInner<T>(props: HeatmapProps<T>) {
|
|
104
|
+
const { chartId, height, aspectRatio, fill, ariaLabel, isPending } = props
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<ChartFrame
|
|
108
|
+
series={[]}
|
|
109
|
+
chartId={chartId}
|
|
110
|
+
legend={false}
|
|
111
|
+
{...(height !== undefined && { height })}
|
|
112
|
+
{...(aspectRatio !== undefined && { aspectRatio })}
|
|
113
|
+
{...(fill !== undefined && { fill })}
|
|
114
|
+
{...(ariaLabel !== undefined && { ariaLabel })}
|
|
115
|
+
{...(isPending !== undefined && { isPending })}
|
|
116
|
+
>
|
|
117
|
+
{(plot) => <HeatmapPlot {...props} plot={plot} />}
|
|
118
|
+
</ChartFrame>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type HeatmapPlotProps<T> = HeatmapProps<T> & {
|
|
123
|
+
plot: { width: number; height: number; hidden: ReadonlySet<string> }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** The measured plot — split from {@link HeatmapInner} so the grid only draws once `ChartFrame`
|
|
127
|
+
* has resolved a non-empty plot rect. */
|
|
128
|
+
function HeatmapPlot<T>(props: HeatmapPlotProps<T>) {
|
|
99
129
|
const {
|
|
100
130
|
data,
|
|
101
|
-
|
|
102
|
-
height,
|
|
131
|
+
plot,
|
|
103
132
|
chartId,
|
|
104
133
|
getRow,
|
|
105
134
|
getCol,
|
|
@@ -115,11 +144,10 @@ function HeatmapInner<T>(props: HeatmapProps<T>) {
|
|
|
115
144
|
colLabel = (c) => c,
|
|
116
145
|
renderTooltip,
|
|
117
146
|
legend,
|
|
118
|
-
isPending,
|
|
119
147
|
} = props
|
|
148
|
+
const { width, height } = plot
|
|
120
149
|
|
|
121
|
-
const
|
|
122
|
-
const { tip, show, hide, tooltipRef } = useChartTooltip<HeatmapCell>()
|
|
150
|
+
const [tip, setTip] = useState<HeatmapTip | null>(null)
|
|
123
151
|
|
|
124
152
|
const rows = useMemo(() => rowsProp ?? firstSeen(data, getRow), [rowsProp, data, getRow])
|
|
125
153
|
const cols = useMemo(() => colsProp ?? firstSeen(data, getCol), [colsProp, data, getCol])
|
|
@@ -136,12 +164,6 @@ function HeatmapInner<T>(props: HeatmapProps<T>) {
|
|
|
136
164
|
return { lookup: map, max: m }
|
|
137
165
|
}, [data, getRow, getCol, getValue])
|
|
138
166
|
|
|
139
|
-
// Every hook above must still run on a pending render (Rules of Hooks) — the early return comes
|
|
140
|
-
// after them. No `ChartFrame` to forward to here (Heatmap measures via required `width`/`height`
|
|
141
|
-
// props, not `useChartSize`), so the placeholder is rendered directly in its place, same footprint,
|
|
142
|
-
// legend strip and all other content omitted along with it.
|
|
143
|
-
if (isPending) return <ChartPending width={width} height={height} />
|
|
144
|
-
|
|
145
167
|
const legendH = legend ? LEGEND_H + LEGEND_LABEL_H : 0
|
|
146
168
|
const gridW = Math.max(0, width - PAD_LEFT)
|
|
147
169
|
const gridH = Math.max(0, height - PAD_TOP - PAD_BOTTOM - legendH)
|
|
@@ -149,6 +171,11 @@ function HeatmapInner<T>(props: HeatmapProps<T>) {
|
|
|
149
171
|
const cellH = rows.length > 0 ? gridH / rows.length : 0
|
|
150
172
|
const legendGradientId = `${chartId}-heat-legend`
|
|
151
173
|
|
|
174
|
+
const show = (row: string, col: string, value: number, event: PointerEvent<SVGRectElement>) => {
|
|
175
|
+
setTip({ row, col, value, anchor: { x: event.clientX, y: event.clientY } })
|
|
176
|
+
}
|
|
177
|
+
const hide = () => setTip(null)
|
|
178
|
+
|
|
152
179
|
return (
|
|
153
180
|
<div style={{ position: 'relative' }}>
|
|
154
181
|
<svg width={width} height={height}>
|
|
@@ -157,7 +184,7 @@ function HeatmapInner<T>(props: HeatmapProps<T>) {
|
|
|
157
184
|
cols.map((col, ci) => {
|
|
158
185
|
const value = lookup.get(cellKey(row, col))
|
|
159
186
|
const has = value !== undefined
|
|
160
|
-
const
|
|
187
|
+
const cellFill = has ? alpha(color, intensity(value, max)) : alpha(VX.neutral, 0.04)
|
|
161
188
|
return (
|
|
162
189
|
<rect
|
|
163
190
|
key={cellKey(row, col)}
|
|
@@ -166,9 +193,9 @@ function HeatmapInner<T>(props: HeatmapProps<T>) {
|
|
|
166
193
|
width={Math.max(0, cellW - cellGap)}
|
|
167
194
|
height={Math.max(0, cellH - cellGap)}
|
|
168
195
|
rx={cellRadius}
|
|
169
|
-
fill={
|
|
196
|
+
fill={cellFill}
|
|
170
197
|
style={{ cursor: has ? 'pointer' : 'default' }}
|
|
171
|
-
onPointerMove={(e) => has && show(
|
|
198
|
+
onPointerMove={(e) => has && show(row, col, value, e)}
|
|
172
199
|
onPointerLeave={hide}
|
|
173
200
|
onPointerCancel={hide}
|
|
174
201
|
/>
|
|
@@ -245,22 +272,20 @@ function HeatmapInner<T>(props: HeatmapProps<T>) {
|
|
|
245
272
|
)}
|
|
246
273
|
</svg>
|
|
247
274
|
|
|
248
|
-
|
|
249
|
-
{tip
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
<
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
)}
|
|
263
|
-
</ChartTooltip>
|
|
275
|
+
{tip !== null && (
|
|
276
|
+
<ChartTooltipFloat anchor={tip.anchor}>
|
|
277
|
+
<TooltipHeader date={rowLabel(tip.row)} label={colLabel(tip.col)} />
|
|
278
|
+
<TooltipBody>
|
|
279
|
+
<TooltipRow
|
|
280
|
+
color={alpha(color, 0.9)}
|
|
281
|
+
shape="bar"
|
|
282
|
+
label="Value"
|
|
283
|
+
value={formatValue(tip.value)}
|
|
284
|
+
/>
|
|
285
|
+
{renderTooltip?.(tip)}
|
|
286
|
+
</TooltipBody>
|
|
287
|
+
</ChartTooltipFloat>
|
|
288
|
+
)}
|
|
264
289
|
</div>
|
|
265
290
|
)
|
|
266
291
|
}
|