@pond-ts/charts 0.59.0 → 0.60.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/API.md +20 -16
- package/CHANGELOG.md +196 -1
- package/dist/AreaChart.d.ts +53 -1
- package/dist/AreaChart.js +16 -3
- package/dist/BarChart.js +6 -61
- package/dist/BarList.d.ts +22 -0
- package/dist/BarList.js +42 -9
- package/dist/ChartContainer.d.ts +175 -3
- package/dist/ChartContainer.js +190 -11
- package/dist/ChartRow.js +2 -0
- package/dist/Layers.js +14 -4
- package/dist/XAxis.js +19 -14
- package/dist/YAxis.js +2 -2
- package/dist/area.d.ts +43 -1
- package/dist/area.js +122 -5
- package/dist/context.d.ts +35 -2
- package/dist/format.d.ts +1 -1
- package/dist/format.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/theme.d.ts +22 -0
- package/dist/theme.js +3 -0
- package/dist/use-band-ladder.d.ts +30 -0
- package/dist/use-band-ladder.js +81 -0
- package/dist/useChartFrame.d.ts +122 -0
- package/dist/useChartFrame.js +155 -0
- package/dist/useChartLegend.d.ts +8 -0
- package/dist/viewport.d.ts +35 -2
- package/dist/viewport.js +53 -6
- package/dist/yticks.d.ts +5 -1
- package/dist/yticks.js +5 -1
- package/package.json +3 -3
package/API.md
CHANGED
|
@@ -249,17 +249,17 @@ Types: `UseSnapshotOptions`, `SnapshotSource` (structural — covers
|
|
|
249
249
|
|
|
250
250
|
### Components — layout & axes
|
|
251
251
|
|
|
252
|
-
| Component | Key props
|
|
253
|
-
| --------------------------- |
|
|
254
|
-
| `ChartContainer` | `width`, `range?`, `theme?`, `cursor?`, `panZoom?`, `bounds?`, `showAxis?`, `calendar?`, `origin?`, `maxBandWidth?`/`bandAlign?`, `onTrackerChanged?`, `onDrawStats?` | Root: shared x-scale, interactions, annotations | `packages/charts/src/ChartContainer.tsx` |
|
|
255
|
-
| `ChartRow` | `height`, `cursor?` (deprecated — mount a cursor in the row)
|
|
256
|
-
| `Layers` | children
|
|
257
|
-
| `YAxis` | `id` (req), `side?`, `scale?` (`'linear'` \| `'log'` \| `'symlog'`), `linearWindow?`, `min?`/`max?`, `format?`, `width?`, `hide?`
|
|
258
|
-
| `XAxis` | `side?`, `label?`, `format?`, `ticks?`, `transform?`, `dateStyle?`
|
|
259
|
-
| `TimeAxis` / `CategoryAxis` | (XAxis props)
|
|
260
|
-
| `Canvas` | `width`, `height`, `draw`
|
|
261
|
-
| `Selector` | `enabled?` (default `true`), `selected?` (mark \| set), `hovered?`, `onSelect?`, `onHover?`, `children?`
|
|
262
|
-
| `MultiSelector` | `enabled?`, `selected?`, `hovered?`, `sequence?`, `onSelect?`, `onHover?`, `children?`
|
|
252
|
+
| Component | Key props | Purpose | Source |
|
|
253
|
+
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
254
|
+
| `ChartContainer` | `width`, `range?`, `theme?`, `cursor?`, `panZoom?`, `xScale?`, `bounds?`, `showAxis?`, `calendar?`, `origin?`, `maxBandWidth?`/`bandAlign?`, `onTrackerChanged?`, `onDrawStats?` | Root: shared x-scale, interactions, annotations | `packages/charts/src/ChartContainer.tsx` |
|
|
255
|
+
| `ChartRow` | `height`, `cursor?` (deprecated — mount a cursor in the row) | One stacked plot band; owns its y-axes | `packages/charts/src/ChartRow.tsx` |
|
|
256
|
+
| `Layers` | children | Mandatory z-stack inside a row (back-to-front) | `packages/charts/src/Layers.tsx` |
|
|
257
|
+
| `YAxis` | `id` (req), `side?`, `scale?` (`'linear'` \| `'log'` \| `'symlog'`), `linearWindow?`, `min?`/`max?`, `format?`, `width?`, `hide?` | Y-axis gutter; layers bind via their `axis` prop | `packages/charts/src/YAxis.tsx` |
|
|
258
|
+
| `XAxis` | `side?`, `label?`, `format?`, `ticks?`, `transform?`, `dateStyle?` | Placeable x-axis strip; kind inferred from data | `packages/charts/src/XAxis.tsx` |
|
|
259
|
+
| `TimeAxis` / `CategoryAxis` | (XAxis props) | Thin `XAxis` presets | `packages/charts/src/TimeAxis.tsx`, `CategoryAxis.tsx` |
|
|
260
|
+
| `Canvas` | `width`, `height`, `draw` | Low-level DPR-aware canvas primitive | `packages/charts/src/Canvas.tsx` |
|
|
261
|
+
| `Selector` | `enabled?` (default `true`), `selected?` (mark \| set), `hovered?`, `onSelect?`, `onHover?`, `children?` | Wraps its scope; mounting enables click-select and owns the state it drives (RFC A10) | `packages/charts/src/selectors.tsx` |
|
|
262
|
+
| `MultiSelector` | `enabled?`, `selected?`, `hovered?`, `sequence?`, `onSelect?`, `onHover?`, `children?` | Sweep-select superset of `Selector`: drag sweeps marks, release reports `(hits, modifiers, spans)` — plural, one per swept layer (RFC A5.2) | `packages/charts/src/selectors.tsx` |
|
|
263
263
|
|
|
264
264
|
### Components — draw layers
|
|
265
265
|
|
|
@@ -280,7 +280,7 @@ schema columns). Because the union splits per series _kind_, a value typed as
|
|
|
280
280
|
| Component | Data props | Purpose | Source |
|
|
281
281
|
| -------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -------------------------------------- |
|
|
282
282
|
| `LineChart` | `column`, `gaps?`, `sessionBreaks?` | Gap-aware line | `packages/charts/src/LineChart.tsx` |
|
|
283
|
-
| `AreaChart` | `column`, `baseline?`, `gaps?`
|
|
283
|
+
| `AreaChart` | `column`, `baseline?`, `gaps?`, `thresholds?`/`bandColors?` | Filled area | `packages/charts/src/AreaChart.tsx` |
|
|
284
284
|
| `BandChart` | `lower`, `upper` | Variance-band envelope | `packages/charts/src/BandChart.tsx` |
|
|
285
285
|
| `ScatterChart` | `column`, `id?` (selection), radius/color encodings | Points; data-driven size/colour | `packages/charts/src/ScatterChart.tsx` |
|
|
286
286
|
| `BarChart` | `column` \| `columns` \| `bins` \| `categories`, `orientation?`, `thresholds?`/`bandColors?` | Bars, stacked bars, histograms, categorical | `packages/charts/src/BarChart.tsx` |
|
|
@@ -328,10 +328,10 @@ label + data cells, `sortBy`/`sort`, optional per-row expander. The in-plot
|
|
|
328
328
|
histogram stays `<BarChart orientation="horizontal">` — these are the table
|
|
329
329
|
shape (react-timeseries-charts' `HorizontalBarChart`).
|
|
330
330
|
|
|
331
|
-
| Component | Data props
|
|
332
|
-
| --------- |
|
|
333
|
-
| `BarList` | `rows`, `columns` (`values` names), `sortBy?`, `before?`/`after?`, `renderExpanded?` | Ranked bar list — one proportional bar line per column per row | `packages/charts/src/BarList.tsx` |
|
|
334
|
-
| `BoxList` | `rows`, `columns` (five-number names + `value?` tick), same table props
|
|
331
|
+
| Component | Data props | Purpose | Source |
|
|
332
|
+
| --------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | --------------------------------- |
|
|
333
|
+
| `BarList` | `rows`, `columns` (`values` names), `barColors?`, `sortBy?`, `before?`/`after?`, `renderExpanded?` | Ranked bar list — one proportional bar line per column per row | `packages/charts/src/BarList.tsx` |
|
|
334
|
+
| `BoxList` | `rows`, `columns` (five-number names + `value?` tick), same table props | Distribution list — range band / q1→q3 body / median / current tick | `packages/charts/src/BoxList.tsx` |
|
|
335
335
|
|
|
336
336
|
Row/option types + readers (`packages/charts/src/list.ts`): `ListRow`,
|
|
337
337
|
`ListValue`, `ListCellSpec`, `ListMarker` (reference rule through every row,
|
|
@@ -411,6 +411,10 @@ Series shapes (same file): `ChartSeries`, `BandSeries`, `BoxSeries`,
|
|
|
411
411
|
| `SwatchSpec` / `LegendItemInput` | Legend swatch vocabulary + explicit-rows input (`<Legend items>`) | `packages/charts/src/swatch.ts` |
|
|
412
412
|
| `useChartLegend` | Headless legend hook: rows (items grouped by chart row) + `hover`/`select` verbs | `packages/charts/src/useChartLegend.ts` |
|
|
413
413
|
| `ChartLegend` / `LegendRow` / `LegendItem` | The hook's return shape (`rows` group `items`; items carry `selected`/`hovered`) | `packages/charts/src/useChartLegend.ts` |
|
|
414
|
+
| `useChartFrame` | Resolved plot geometry: plot rect, gutters, x scale, a row's y scales, band slot edges | `packages/charts/src/useChartFrame.ts` |
|
|
415
|
+
| `ChartFrame` / `ChartFrameRow` | The hook's return shape — container x half, plus a row y half that is `null` outside a `<ChartRow>` | `packages/charts/src/useChartFrame.ts` |
|
|
416
|
+
| `ChartBands` / `ChartBand` | Ordinal slot geometry on a category axis (`count`/`pitch`/`labels`/`at(i)`); `null` on time/value | `packages/charts/src/useChartFrame.ts` |
|
|
417
|
+
| `ChartXScale` | The union the container's shared x scale resolves to (time / linear / trading / band / elapsed) | `packages/charts/src/context.ts` |
|
|
414
418
|
| `LegendPlacement` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `packages/charts/src/Legend.tsx` |
|
|
415
419
|
| `Curve` | Path interpolation: `'linear' \| 'monotone' \| 'natural' \| 'basis' \| 'step'` | `packages/charts/src/curve.ts` |
|
|
416
420
|
| `RadiusEncoding` / `ColorEncoding` | Data-driven scatter size/colour | `packages/charts/src/encoding.ts` |
|
package/CHANGELOG.md
CHANGED
|
@@ -8,7 +8,8 @@ The `@pond-ts` packages — `pond-ts`, `@pond-ts/react`, `@pond-ts/charts`,
|
|
|
8
8
|
under a single `v*` tag, so this file covers them all. Pre-1.0: minor bumps may
|
|
9
9
|
include new features and type-level changes; patch bumps are strictly additive.
|
|
10
10
|
|
|
11
|
-
[Unreleased]: https://github.com/pond-ts/pond/compare/v0.
|
|
11
|
+
[Unreleased]: https://github.com/pond-ts/pond/compare/v0.60.0...HEAD
|
|
12
|
+
[0.60.0]: https://github.com/pond-ts/pond/compare/v0.59.0...v0.60.0
|
|
12
13
|
[0.59.0]: https://github.com/pond-ts/pond/compare/v0.58.0...v0.59.0
|
|
13
14
|
[0.58.0]: https://github.com/pond-ts/pond/compare/v0.57.0...v0.58.0
|
|
14
15
|
[0.57.0]: https://github.com/pond-ts/pond/compare/v0.56.2...v0.57.0
|
|
@@ -62,6 +63,200 @@ include new features and type-level changes; patch bumps are strictly additive.
|
|
|
62
63
|
|
|
63
64
|
## [Unreleased]
|
|
64
65
|
|
|
66
|
+
## [0.60.0] — 2026-08-13
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- `@pond-ts/charts`: `<AreaChart thresholds>` + `bandColors` — threshold
|
|
71
|
+
banding along the area's height ([PND-BANDAREA]), the area counterpart of
|
|
72
|
+
`<BarChart thresholds>`. `n` breakpoints (absolute data values, magnitude-
|
|
73
|
+
mirrored below zero) make `n + 1` bands; fills resolve `bandColors` → the
|
|
74
|
+
new `AreaStyle.bands` theme token (the default theme ships the same
|
|
75
|
+
teal/amber/red ladder as the bar role). One hard-stop pixel-space gradient
|
|
76
|
+
carries the ladder for the fill **and** the outline, so the value line
|
|
77
|
+
switches hue exactly at each crossing and the banded area keeps one hit
|
|
78
|
+
region, one legend row and one readout identity. Composes with `curve`,
|
|
79
|
+
`gaps` and M4 decimation unchanged; a swept window keeps the band colours
|
|
80
|
+
(no `spanColor` swap). Ladder resolution + dev warnings shared with
|
|
81
|
+
`<BarChart>` via one internal hook.
|
|
82
|
+
- **charts: `<ChartContainer xScale="log" | "symlog">` — a logarithmic value x
|
|
83
|
+
axis** ([#649]). The x counterpart of `<YAxis scale>`, for a quantity spanning
|
|
84
|
+
orders of magnitude — a power–duration curve is watts against 1s · 5s · 1m ·
|
|
85
|
+
20m · 3h, which is unreadable on a linear x.
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
<ChartContainer range={[1, 10800]} xScale="log">
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Why the container and not `<XAxis scale>`**, where the `<YAxis>` mirror would
|
|
92
|
+
put it: there is one x scale shared by every row and the container builds it,
|
|
93
|
+
while every `<XAxis>` prop is presentational (`format`, `label`, `side`,
|
|
94
|
+
`ticks`, `align`, …). `<YAxis>` is the opposite — one scale per axis per row,
|
|
95
|
+
declared by the axis, which is why `min`/`max`/`pad`/`scale` live there. It
|
|
96
|
+
sits beside `origin`, `spacing` and `calendar`, which shape the same scale.
|
|
97
|
+
|
|
98
|
+
Ignored on a time or category axis. A `'log'` domain reaching zero **falls back
|
|
99
|
+
to linear and warns** rather than silently clamping — `log(0)` is undefined;
|
|
100
|
+
use `'symlog'` for data that crosses zero.
|
|
101
|
+
|
|
102
|
+
Nothing downstream branches: d3's log scales share the continuous-scale
|
|
103
|
+
surface, so draw layers are untouched. The tick ladder is the one the y axis
|
|
104
|
+
already built (`tickValues`, renamed from `yTickValues` now that both axes use
|
|
105
|
+
it) — d3's raw `scaleLog.ticks()` is nearly a step function.
|
|
106
|
+
|
|
107
|
+
[#649]: https://github.com/pond-ts/pond/issues/649
|
|
108
|
+
|
|
109
|
+
- **charts: `<BarList barColors>` — per-row bar colour** ([#650]). The list's
|
|
110
|
+
counterpart to `<BarChart binColors>`: `barColors[i]` aligned to the rows you
|
|
111
|
+
passed, an `undefined` or short entry falling back to the column's `as` /
|
|
112
|
+
theme fill.
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<BarList rows={zones} columns={[{ column: 'frac' }]} barColors={ZONE_RAMP} />
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
For the case `binColors` was built for and a list could not do — a zone table
|
|
119
|
+
where each row's bar carries its own step of a ramp. A `BarListColumn`'s
|
|
120
|
+
single `as` paints every row the same colour, so the ramp had to move onto the
|
|
121
|
+
row label, putting it on the wrong element: the bar is the natural carrier of
|
|
122
|
+
a magnitude.
|
|
123
|
+
|
|
124
|
+
**Colours key on the row, not its render position**, so they follow the data
|
|
125
|
+
through a `sortBy` rather than repainting the ramp onto whichever rows now sit
|
|
126
|
+
in those slots.
|
|
127
|
+
|
|
128
|
+
**A per-row colour makes the fill load-bearing, so its state treatment stands
|
|
129
|
+
down** — a coloured bar keeps its own colour while selected, and shows the
|
|
130
|
+
state in opacity instead. That is the rule a multi-metric row already
|
|
131
|
+
followed, and the one `binColors` follows on the canvas: recolouring a bar
|
|
132
|
+
that means something trades a distinction the reader needs for one the band
|
|
133
|
+
and rail already give them.
|
|
134
|
+
|
|
135
|
+
[#650]: https://github.com/pond-ts/pond/issues/650
|
|
136
|
+
|
|
137
|
+
- **charts: `<ChartContainer categories>` — the ordinal axis as a
|
|
138
|
+
container-level choice** ([PND-IGNITECAT]). Declare the slot names on the
|
|
139
|
+
container and **any value-keyed layer can live on them** — a target line, a
|
|
140
|
+
point mark or a filled envelope over categorical bars, which was previously
|
|
141
|
+
not expressible at all.
|
|
142
|
+
|
|
143
|
+
The band scale used to be reachable only _through a layer_: `<BarChart
|
|
144
|
+
categories>` and a **horizontal** heat map reported `xKind: 'category'`, every other layer
|
|
145
|
+
reported `'time'` or `'value'`, and a container throws on a mixed kind. The
|
|
146
|
+
workaround — key every layer to a synthetic integer index and hand-supply the
|
|
147
|
+
tick labels — forfeits two features the ordinal axis already implements, and
|
|
148
|
+
both came back as their own friction entries: `<XAxis>` label thinning (gated
|
|
149
|
+
on a category axis with no custom ticks) and the `maxBandWidth` / `bandAlign`
|
|
150
|
+
slot packing. Declaring the categories on the container keeps both.
|
|
151
|
+
|
|
152
|
+
The change is small because the scale was already built for it: `scaleBand`'s
|
|
153
|
+
domain is **numeric** (`[0, n]`, slot `i` at `[i, i+1]`) with a linear pixel
|
|
154
|
+
mapping, so a `ValueSeries` keyed on slot coordinates already lands where the
|
|
155
|
+
bars do. **Slot `i`'s centre is `i + 0.5`** — the same number
|
|
156
|
+
`ScaleBand.ticks()` returns and where `<XAxis>` puts the tick.
|
|
157
|
+
|
|
158
|
+
Two things error, deliberately: a **time-keyed layer** (a timestamp has no
|
|
159
|
+
slot), and a **category layer that disagrees** with the prop in content or
|
|
160
|
+
order — the prop is authoritative, and a silent mismatch would draw bars
|
|
161
|
+
under the wrong labels. The pre-existing mixed-kind error now names the prop
|
|
162
|
+
as the fix.
|
|
163
|
+
|
|
164
|
+
Declaring it has two costs, both already true of an inferred category axis
|
|
165
|
+
and now reachable from a previously-continuous container: **x pan and zoom
|
|
166
|
+
stop** (`panZoom` keeps working on y), and **`range` stops applying to x**
|
|
167
|
+
(the domain is `[0, n]` from the slot count, so an x range is a no-op).
|
|
168
|
+
|
|
169
|
+
One hazard is documented rather than enforced: **a value-keyed layer is taken
|
|
170
|
+
at its word**, so a layer whose x means something other than a slot
|
|
171
|
+
coordinate — a horizontal categorical `<BarChart>`, whose x is bar _length_ —
|
|
172
|
+
will draw in the wrong place. A guard for that case was written and removed
|
|
173
|
+
after review: it tested `binCategories`, which is the generic "my _y_ is
|
|
174
|
+
ordinal" channel that a **vertical heat map** sets for its rows, so it
|
|
175
|
+
rejected a slot-keyed grid with named columns on x — a wanted layout, since
|
|
176
|
+
ordinal rows plus ordinal columns is just a 2-D grid. Nothing distinguishes
|
|
177
|
+
"my x is a coordinate" from "my x is a magnitude", so there is no
|
|
178
|
+
contradiction to detect.
|
|
179
|
+
|
|
180
|
+
`categories={[]}` is an ordinal axis with **no slots yet**, not a fallback to
|
|
181
|
+
time — so the kind doesn't flip and rebuild every scale when data arrives.
|
|
182
|
+
|
|
183
|
+
Omitting `categories` leaves the inferred behaviour exactly as it was.
|
|
184
|
+
|
|
185
|
+
- **charts: `useChartFrame()` — the resolved plot geometry, published**
|
|
186
|
+
([PND-IGNITEFRAME]). A hook returning what the container already worked out:
|
|
187
|
+
the plot rect (`plot.x` / `plot.width`), the reserved axis `gutters`, the
|
|
188
|
+
shared `xScale` and its `xKind`, a row's `yScales` and top inset, and — on a
|
|
189
|
+
category axis — the ordinal slot edges (`bands.at(i)`, `pitch`, `labels`).
|
|
190
|
+
|
|
191
|
+
Consumers aligning DOM chrome to the plot (per-slot header tables, column
|
|
192
|
+
summary strips, cards pinned over a band, a colour ramp keyed to the plot's
|
|
193
|
+
own scale) previously had to re-derive all of it: pin every axis gutter to a
|
|
194
|
+
fixed width so it stops depending on label content, measure the outer box,
|
|
195
|
+
subtract, and re-implement the band packing. **That duplicate is not merely
|
|
196
|
+
verbose — it is wrong over time.** It holds only until the library changes
|
|
197
|
+
how a gutter is sized or how bands are packed, at which point the chrome
|
|
198
|
+
slides out of alignment with the plot it labels, with no type error and no
|
|
199
|
+
failing test.
|
|
200
|
+
|
|
201
|
+
Two shape notes. **The x/y split is the library's own** — the container owns
|
|
202
|
+
one shared x scale, rows own their y scales — so `plot` carries x and `row`
|
|
203
|
+
carries y, and `row` is `null` when the hook is called outside a
|
|
204
|
+
`<ChartRow>`. That `null` is deliberate: the common case (a header strip
|
|
205
|
+
beside the rows) genuinely has no y geometry, and reporting `height: 0`
|
|
206
|
+
instead would be the same silent misalignment the hook exists to remove.
|
|
207
|
+
**Scope follows placement**, exactly as `useChartLegend` already does.
|
|
208
|
+
|
|
209
|
+
`useChartLegend`'s `gutters` is unchanged and still the right call for a
|
|
210
|
+
legend; it now documents `useChartFrame()` as the fuller surface. It was the
|
|
211
|
+
only geometry the library published, for one consumer, on a hook named for
|
|
212
|
+
something else — which is why this exists.
|
|
213
|
+
|
|
214
|
+
- **charts: `<ChartContainer width="auto">` — fill the available width**
|
|
215
|
+
([PND-WIDTH]). `width` now accepts `'auto'`, and an omitted `width` means the
|
|
216
|
+
same; a number still skips the measure pass and paints on the first render.
|
|
217
|
+
The container renders a plain full-width box, measures it with a
|
|
218
|
+
`ResizeObserver`, and mounts the chart at that pixel width — the canvas
|
|
219
|
+
renderer needs real pixels to lay out ticks and slots, so this is measurement
|
|
220
|
+
moved inside the library rather than a percentage handed to a canvas. Nothing
|
|
221
|
+
paints until a real width exists.
|
|
222
|
+
|
|
223
|
+
This is the shipped
|
|
224
|
+
[responsive-width recipe](https://pond-ts.github.io/pond/docs/recipes/responsive-width)
|
|
225
|
+
become the implementation, and it closes that recipe's sharpest edge by
|
|
226
|
+
construction: the measured box is one the library owns, so it can never be
|
|
227
|
+
the caller's padded or bordered box (whose border-box width overflowed the
|
|
228
|
+
chart by exactly the padding, silently clipped when the box also hid
|
|
229
|
+
overflow). Style your own wrapper freely.
|
|
230
|
+
|
|
231
|
+
Two behaviours worth knowing. A container **hidden** by an ancestor's
|
|
232
|
+
`display: none` keeps the last width it measured and stays mounted, so a tab
|
|
233
|
+
switch does not discard pan/zoom position, selection or hover — writing the
|
|
234
|
+
zero measurement through would unmount and rebuild all of it. And `'auto'`
|
|
235
|
+
needs a parent with a **definite** width: a parent sized by its own content
|
|
236
|
+
(a float, an `inline-block`, a grid `auto` track, a flex child without
|
|
237
|
+
`min-width: 0`) measures 0, and the chart is the content that would have
|
|
238
|
+
given it a width, so the chart stays blank with no error.
|
|
239
|
+
|
|
240
|
+
Three independent consumers reported the explicit-pixel requirement; the
|
|
241
|
+
third was multiplying the same ~25-line measure-and-gate hook across seven
|
|
242
|
+
panes.
|
|
243
|
+
|
|
244
|
+
### Changed
|
|
245
|
+
|
|
246
|
+
- **charts: `ChartContainerProps.width` is now `number | 'auto'` and optional**
|
|
247
|
+
(was a required `number`). Strictly additive for callers passing a number.
|
|
248
|
+
|
|
249
|
+
### Fixed
|
|
250
|
+
|
|
251
|
+
- **charts: value-axis pan and zoom no longer snap to whole integers**
|
|
252
|
+
(shipped inside [#653]). `panRange`/`zoomRange` were written for a
|
|
253
|
+
millisecond axis and silently assumed every axis was one, so a value domain
|
|
254
|
+
of `[0.5, 10800]` snapped its floor to `0` and `[0.001, 1]` collapsed to
|
|
255
|
+
`[0, 1]` — fatal under a log axis, where `log(0)` is undefined. Gestures now
|
|
256
|
+
snap only on a **time** axis (`ViewportOptions.snap`), and a log x axis pans
|
|
257
|
+
by ratio and zooms in log space, keeping the value under the cursor fixed.
|
|
258
|
+
Time-axis behaviour is unchanged.
|
|
259
|
+
|
|
65
260
|
## [0.59.0] — 2026-08-11
|
|
66
261
|
|
|
67
262
|
### Added
|
package/dist/AreaChart.d.ts
CHANGED
|
@@ -75,6 +75,58 @@ export interface AreaChartCommon<S extends SeriesSchema = SeriesSchema, VS exten
|
|
|
75
75
|
* `DecimateOption`.
|
|
76
76
|
*/
|
|
77
77
|
decimate?: DecimateOption;
|
|
78
|
+
/**
|
|
79
|
+
* **Threshold breakpoints** ([PND-BANDAREA]) — colour the area *along its
|
|
80
|
+
* height* against a ladder, so the fill (and the value line on its top edge)
|
|
81
|
+
* shows which zone each stretch of the series sits in: low / medium / high
|
|
82
|
+
* as bands that switch exactly at the breakpoints. Breakpoints are
|
|
83
|
+
* **absolute data values** in the axis's own units — `[1, 2]` means
|
|
84
|
+
* "warning above 1, alarm above 2", not offsets from the baseline — and `n`
|
|
85
|
+
* of them make `n + 1` bands. Each must be finite and greater than zero;
|
|
86
|
+
* anything else is dropped with a dev warning (the ladder is walked on the
|
|
87
|
+
* magnitude, so a negative breakpoint is not expressible).
|
|
88
|
+
*
|
|
89
|
+
* ```tsx
|
|
90
|
+
* // neutral to 1, warning 1–2, alarm above 2
|
|
91
|
+
* <AreaChart series={s} column="value" thresholds={[1, 2]} />
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* Band fills come from {@link AreaStyle.bands} on the resolved role
|
|
95
|
+
* (`theme.area[as] ?? theme.area.default`), overridden by {@link bandColors}.
|
|
96
|
+
* Breakpoints are data and live here; colour stays in the theme — the same
|
|
97
|
+
* split `<BarChart thresholds>` uses ([PND-BANDBAR2]), and the same
|
|
98
|
+
* magnitude-mirrored reading: values below zero (an above/below-axis area
|
|
99
|
+
* with `baseline={0}`) walk the same ±ladder without negative breakpoints.
|
|
100
|
+
*
|
|
101
|
+
* **A banded area is still one area.** One hit region, one legend row, one
|
|
102
|
+
* readout identity; hover / selection strengthen the fill and keep the band
|
|
103
|
+
* colours, and a swept window's `spanColor` single-hue swap is skipped for
|
|
104
|
+
* the same reason the banded bar keeps its own colours — one hue would
|
|
105
|
+
* erase the very thing the bands encode. The banded fill is **flat** (the
|
|
106
|
+
* grade to transparent at the baseline is dropped): the fade encoded
|
|
107
|
+
* distance-from-baseline, which the ladder now states discretely. The
|
|
108
|
+
* outline strokes in the band hues too, switching exactly at each crossing.
|
|
109
|
+
*
|
|
110
|
+
* Composes with `curve`, `gaps` and `decimate` unchanged — banding rides
|
|
111
|
+
* the paint, not the geometry, so M4 decimation stays on (unlike the bar
|
|
112
|
+
* envelope, which collapses many bars into one rect and so cannot carry
|
|
113
|
+
* per-band colour). The inferred gap connectors (`'dashed'` / `'step'` /
|
|
114
|
+
* `'fade'`) keep the role's line colour: they are guesses about absent
|
|
115
|
+
* data, and a zone colour would over-claim exactly where nothing was
|
|
116
|
+
* measured.
|
|
117
|
+
*/
|
|
118
|
+
thresholds?: readonly number[];
|
|
119
|
+
/**
|
|
120
|
+
* Call-site override for the {@link thresholds} band fills — `bandColors[k]`
|
|
121
|
+
* paints the band above `thresholds[k - 1]`, so a ladder of `n` thresholds
|
|
122
|
+
* reads `n + 1` entries. Omitted ⇒ {@link AreaStyle.bands} from the theme.
|
|
123
|
+
*
|
|
124
|
+
* Prefer the theme for anything a design system owns; this is the escape
|
|
125
|
+
* hatch for a one-off ladder that shouldn't mint a theme role. If neither
|
|
126
|
+
* source supplies enough entries, the shortfall falls back to the flat fill
|
|
127
|
+
* and dev-warns rather than silently drawing an unbanded area.
|
|
128
|
+
*/
|
|
129
|
+
bandColors?: readonly string[];
|
|
78
130
|
/**
|
|
79
131
|
* This layer's `<Legend>` row: `false` ⇒ no row (opt out), a string ⇒ the
|
|
80
132
|
* row's display name. **Omitted ⇒ a row named by the layer's readout
|
|
@@ -151,6 +203,6 @@ export declare function resolveAreaBaseline(baseline: number | undefined, yScale
|
|
|
151
203
|
* </Layers>
|
|
152
204
|
* ```
|
|
153
205
|
*/
|
|
154
|
-
export declare function AreaChart<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema>({ series, column, readout, as: semantic, axis, id, baseline, curve, gaps, decimate, legend, index, }: AreaChartProps<S, VS>): null;
|
|
206
|
+
export declare function AreaChart<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema>({ series, column, readout, as: semantic, axis, id, baseline, curve, gaps, decimate, thresholds, bandColors, legend, index, }: AreaChartProps<S, VS>): null;
|
|
155
207
|
export {};
|
|
156
208
|
//# sourceMappingURL=AreaChart.d.ts.map
|
package/dist/AreaChart.js
CHANGED
|
@@ -9,6 +9,7 @@ import { DEFAULT_GAP_MODE, DEFAULT_GAP_CONNECTOR_OPACITY, } from './gaps.js';
|
|
|
9
9
|
import { ContainerContext, LayersContext, } from './context.js';
|
|
10
10
|
import { legendLabelFor, useLegendItems, } from './swatch.js';
|
|
11
11
|
import { useSlotKey } from './use-slot-key.js';
|
|
12
|
+
import { useBandLadder } from './use-band-ladder.js';
|
|
12
13
|
/** Read a d3 linear scale's domain lower bound (the axis floor) from the plain
|
|
13
14
|
* `(value) => pixel` function the row hands to `draw`. The runtime object is a
|
|
14
15
|
* d3 `ScaleLinear` (it carries `.domain()`); the {@link RowLayer} type narrows
|
|
@@ -56,7 +57,7 @@ function domainFloor(yScale) {
|
|
|
56
57
|
* </Layers>
|
|
57
58
|
* ```
|
|
58
59
|
*/
|
|
59
|
-
export function AreaChart({ series, column, readout, as: semantic, axis, id, baseline, curve, gaps = DEFAULT_GAP_MODE, decimate = true, legend, index = 0, }) {
|
|
60
|
+
export function AreaChart({ series, column, readout, as: semantic, axis, id, baseline, curve, gaps = DEFAULT_GAP_MODE, decimate = true, thresholds, bandColors, legend, index = 0, }) {
|
|
60
61
|
const container = useContext(ContainerContext);
|
|
61
62
|
if (container === null) {
|
|
62
63
|
throw new Error('<AreaChart> must be rendered inside a <ChartContainer>');
|
|
@@ -87,6 +88,11 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
87
88
|
// Styling: semantic identifier → theme area style. The single styling channel.
|
|
88
89
|
const { area } = container.theme;
|
|
89
90
|
const style = (semantic !== undefined ? area[semantic] : undefined) ?? area.default;
|
|
91
|
+
// ── Threshold ladder ([PND-BANDAREA]) — breakpoints normalized + paired
|
|
92
|
+
// with `bandColors` → the role's `AreaStyle.bands` in the shared
|
|
93
|
+
// {@link useBandLadder} (one contract with `<BarChart thresholds>`,
|
|
94
|
+
// including every dev warning).
|
|
95
|
+
const bandLadder = useBandLadder('AreaChart', thresholds, bandColors, style.bands, style.fill);
|
|
90
96
|
// Series identity for the readout (the `as` role, else the column name).
|
|
91
97
|
const label = semantic ?? column;
|
|
92
98
|
const curveFactory = resolveCurve(curve);
|
|
@@ -249,7 +255,13 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
249
255
|
strokeSpanEdges(ctx, [xScale(spanX[0]), xScale(spanX[1])], ctx.canvas.height, container.theme.annotation?.spanEdge ?? '#f0b26b');
|
|
250
256
|
const [outStyle, outAlpha] = areaStateStyle(style, 'dimmed');
|
|
251
257
|
const [inStyle] = areaStateStyle(style, 'selected');
|
|
252
|
-
return drawPartitioned(ctx, [xScale(spanX[0]), xScale(spanX[1])], plotExtentOf(ctx, xScale, yScale).height, fill(outStyle, outAlpha), fill(
|
|
258
|
+
return drawPartitioned(ctx, [xScale(spanX[0]), xScale(spanX[1])], plotExtentOf(ctx, xScale, yScale).height, fill(outStyle, outAlpha), fill(
|
|
259
|
+
// A banded area skips the window's single-hue swap: one hue
|
|
260
|
+
// would erase the very thing the bands encode (the banded bar's
|
|
261
|
+
// rule), so the window strengthens and keeps the ladder.
|
|
262
|
+
style.spanColor === undefined ||
|
|
263
|
+
!soleSpannedTrace ||
|
|
264
|
+
bandLadder !== undefined
|
|
253
265
|
? inStyle
|
|
254
266
|
: { ...inStyle, color: style.spanColor, fill: style.spanColor }, 1), true, 0, plotExtentOf(ctx, xScale, yScale).width);
|
|
255
267
|
function drawAreaWith(st) {
|
|
@@ -262,7 +274,7 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
262
274
|
// `NaN` and poison every coordinate in the fill path. Fall back
|
|
263
275
|
// to the axis floor, which is exactly what an omitted baseline
|
|
264
276
|
// already resolves to.
|
|
265
|
-
resolveAreaBaseline(baseline, yScale), curveFactory, gaps, gapConnectorOpacity, decimate);
|
|
277
|
+
resolveAreaBaseline(baseline, yScale), curveFactory, gaps, gapConnectorOpacity, decimate, bandLadder);
|
|
266
278
|
}
|
|
267
279
|
},
|
|
268
280
|
},
|
|
@@ -281,6 +293,7 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
281
293
|
gaps,
|
|
282
294
|
gapConnectorOpacity,
|
|
283
295
|
decimate,
|
|
296
|
+
bandLadder,
|
|
284
297
|
axis,
|
|
285
298
|
id,
|
|
286
299
|
traceState,
|
package/dist/BarChart.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useContext, useEffect, useMemo } from 'react';
|
|
2
2
|
import { Interval, ValueSeries } from 'pond-ts';
|
|
3
3
|
import { barsFromTimeSeries, barsFromBins, barsFromValueSeries, categoryStack, categoryStacks, stacksFromBins, stacksFromColumns, stacksFromGroups, } from './data.js';
|
|
4
|
-
import { barAt, barExtent, barIndexAtTime, drawBars, drawStacks,
|
|
4
|
+
import { barAt, barExtent, barIndexAtTime, drawBars, drawStacks, resolveBarBaseline, stackAt, stackBinExtent, stackValueExtent, } from './bars.js';
|
|
5
5
|
import { spansForLayer } from './span.js';
|
|
6
|
+
import { useBandLadder } from './use-band-ladder.js';
|
|
6
7
|
import { isDev } from './dev.js';
|
|
7
8
|
import { ContainerContext, LayersContext, } from './context.js';
|
|
8
9
|
import { sweep1D } from './sweep.js';
|
|
@@ -278,66 +279,10 @@ export function BarChart({ series, bins, categories, column, columns, as: semant
|
|
|
278
279
|
? { ...singleStyle, maxWidth: maxBarWidth }
|
|
279
280
|
: singleStyle, [singleStyle, maxBarWidth]);
|
|
280
281
|
// ── Threshold ladder ([PND-BANDBAR2]) ────────────────────────────────────
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
// because a quietly-unbanded bar was the workaround's failure mode.
|
|
286
|
-
// Value-compare the two array props rather than relying on their identity.
|
|
287
|
-
// `thresholds={[1, 2]}` inline is the documented usage and the shape every
|
|
288
|
-
// story and doc example uses — and a fresh array each render would rebuild
|
|
289
|
-
// the ladder, hence the layer `entry` below, hence a `registerLayer` call
|
|
290
|
-
// **every render**. That is a repaint treadmill, not just a noisy warning.
|
|
291
|
-
// The same value-compare-on-registration reasoning `<YAxis ticks>` already
|
|
292
|
-
// applies.
|
|
293
|
-
const thresholdKey = thresholds === undefined ? '' : thresholds.join(',');
|
|
294
|
-
const bandColorKey = bandColors === undefined ? '' : bandColors.join(',');
|
|
295
|
-
const bandLadder = useMemo(() => {
|
|
296
|
-
const steps = normalizeThresholds(thresholds);
|
|
297
|
-
if (steps === null) {
|
|
298
|
-
if (isDev && thresholds !== undefined && thresholds.length > 0) {
|
|
299
|
-
console.warn('<BarChart thresholds>: no usable breakpoints, so no banding was ' +
|
|
300
|
-
'applied — each must be finite and greater than zero. Bars draw ' +
|
|
301
|
-
'in the flat fill.');
|
|
302
|
-
}
|
|
303
|
-
return undefined;
|
|
304
|
-
}
|
|
305
|
-
// Some, but not all, entries dropped. Silently banding on a subset of what
|
|
306
|
-
// the caller wrote is exactly the class of quiet wrongness this feature is
|
|
307
|
-
// meant to remove, so say so.
|
|
308
|
-
if (isDev && thresholds !== undefined && steps.length < thresholds.length) {
|
|
309
|
-
console.warn(`<BarChart thresholds>: dropped ${thresholds.length - steps.length} ` +
|
|
310
|
-
'breakpoint(s) that were not finite and greater than zero. The ' +
|
|
311
|
-
'ladder is walked on the magnitude and mirrored onto whichever side ' +
|
|
312
|
-
'of zero a bar is on, so a negative breakpoint has no meaning; ' +
|
|
313
|
-
`banding on [${steps.join(', ')}].`);
|
|
314
|
-
}
|
|
315
|
-
const want = steps.length + 1;
|
|
316
|
-
const supplied = bandColors ?? singleStyle.bands;
|
|
317
|
-
if (supplied === undefined || supplied.length === 0) {
|
|
318
|
-
if (isDev) {
|
|
319
|
-
console.warn(`<BarChart thresholds>: ${steps.length} breakpoint(s) need ${want} ` +
|
|
320
|
-
'band colours, but neither `bandColors` nor the theme role’s ' +
|
|
321
|
-
'`BarStyle.bands` supplies any. Bars draw in the flat fill.');
|
|
322
|
-
}
|
|
323
|
-
return undefined;
|
|
324
|
-
}
|
|
325
|
-
if (supplied.length < want && isDev) {
|
|
326
|
-
console.warn(`<BarChart thresholds>: ${steps.length} breakpoint(s) need ${want} ` +
|
|
327
|
-
`band colours but only ${supplied.length} were supplied; bands ` +
|
|
328
|
-
'above the last colour fall back to the flat fill.');
|
|
329
|
-
}
|
|
330
|
-
// Pad a short ladder with the flat fill so the draw path can index freely.
|
|
331
|
-
const resolved = supplied.length >= want
|
|
332
|
-
? supplied.slice(0, want)
|
|
333
|
-
: [
|
|
334
|
-
...supplied,
|
|
335
|
-
...Array.from({ length: want - supplied.length }, () => singleStyle.fill),
|
|
336
|
-
];
|
|
337
|
-
return { thresholds: steps, colors: resolved };
|
|
338
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- `thresholdKey` /
|
|
339
|
-
// `bandColorKey` are the value-compared stand-ins for the array props.
|
|
340
|
-
}, [thresholdKey, bandColorKey, singleStyle]);
|
|
282
|
+
// Breakpoints normalized + paired with `bandColors` → the role's
|
|
283
|
+
// `BarStyle.bands` in the shared {@link useBandLadder} (one contract with
|
|
284
|
+
// `<AreaChart thresholds>`, including every dev warning).
|
|
285
|
+
const bandLadder = useBandLadder('BarChart', thresholds, bandColors, singleStyle.bands, singleStyle.fill);
|
|
341
286
|
// Conflicts between the ladder and the shapes it can't apply to. In an effect
|
|
342
287
|
// so a re-render doesn't re-log; each fires once per genuinely new pairing.
|
|
343
288
|
const multiGroup = shape.kind === 'stacked' && shape.ss.groups.length > 1;
|
package/dist/BarList.d.ts
CHANGED
|
@@ -69,6 +69,28 @@ export interface BarListCommon<R extends ListRow = ListRow> {
|
|
|
69
69
|
selected?: string | readonly string[] | null;
|
|
70
70
|
/** Row click (rows show the pointer affordance only when provided). */
|
|
71
71
|
onRowClick?: (row: R) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Per-**row** bar colour, `barColors[i]` aligned to the rows in order — the
|
|
74
|
+
* list's `<BarChart binColors>` ([#650]). An `undefined` or short entry falls
|
|
75
|
+
* back to the column's `as` / theme fill, so a partial list is legal.
|
|
76
|
+
*
|
|
77
|
+
* For the case `binColors` was built for and a list could not do: a zone
|
|
78
|
+
* table where each row's bar carries its own step of a ramp (Z1 deep → Z7
|
|
79
|
+
* pale). Without it a `BarListColumn`'s single `as` paints every row the same
|
|
80
|
+
* colour, and the ramp has to move onto the label — putting it on the wrong
|
|
81
|
+
* element, since the bar is the natural carrier of a magnitude.
|
|
82
|
+
*
|
|
83
|
+
* **The fill becomes load-bearing, so its state treatment stands down.** A
|
|
84
|
+
* per-row-coloured bar keeps its own colour while selected or hovered, and
|
|
85
|
+
* the live state is carried by the band and rail that already say it. This is
|
|
86
|
+
* the same rule the multi-metric case follows for the same reason — see the
|
|
87
|
+
* comment beside the fill resolution — and the same one `binColors` follows
|
|
88
|
+
* on the canvas: recolouring a bar that means something would trade a
|
|
89
|
+
* distinction the reader needs for one they already have.
|
|
90
|
+
*
|
|
91
|
+
* [#650]: https://github.com/pond-ts/pond/issues/650
|
|
92
|
+
*/
|
|
93
|
+
barColors?: readonly (string | undefined)[];
|
|
72
94
|
/**
|
|
73
95
|
* **Plural select** — the list's answer to `<MultiSelector>`, and how a user
|
|
74
96
|
* produces a multi-row {@link selected}.
|
package/dist/BarList.js
CHANGED
|
@@ -36,7 +36,7 @@ export function BarList(props) {
|
|
|
36
36
|
// One normalized view of the union — `isSeriesSource` is the runtime
|
|
37
37
|
// narrowing; the doors are mutually exclusive by construction now.
|
|
38
38
|
const source = props;
|
|
39
|
-
const { rows, series, label, columns, domain, sortBy, sortDirection = 'desc', sort, before, after, renderExpanded, defaultExpanded, onExpandToggle, selected, onRowClick, onRowSelect, hovered, onHover, markers, barHeight = 8, divided, baseline, theme = defaultTheme, } = source;
|
|
39
|
+
const { rows, series, label, columns, domain, sortBy, sortDirection = 'desc', sort, before, after, renderExpanded, defaultExpanded, onExpandToggle, selected, onRowClick, onRowSelect, barColors, hovered, onHover, markers, barHeight = 8, divided, baseline, theme = defaultTheme, } = source;
|
|
40
40
|
// A runtime guard for JS consumers and `any`-typed call sites — the
|
|
41
41
|
// props union makes both branches unreachable from typed TS, but a
|
|
42
42
|
// silently-ignored source prop is a worse failure than a throw.
|
|
@@ -49,6 +49,21 @@ export function BarList(props) {
|
|
|
49
49
|
(series instanceof ValueSeries
|
|
50
50
|
? listRowsFromValueSeries(series, label !== undefined ? { label } : {})
|
|
51
51
|
: listRowsFromTimeSeries(series, label !== undefined ? { label } : {})), [rows, series, label]);
|
|
52
|
+
// Keyed by row, not indexed by render position. `barColors` aligns to the
|
|
53
|
+
// rows the caller passed — but the table renders `sorted`, so an index would
|
|
54
|
+
// silently repaint the ramp onto the wrong rows the moment `sortBy` is set.
|
|
55
|
+
// The key survives any reordering.
|
|
56
|
+
const barColorOf = useMemo(() => {
|
|
57
|
+
if (barColors === undefined)
|
|
58
|
+
return null;
|
|
59
|
+
const m = new Map();
|
|
60
|
+
allRows.forEach((r, i) => {
|
|
61
|
+
const c = barColors[i];
|
|
62
|
+
if (c !== undefined)
|
|
63
|
+
m.set(r.key, c);
|
|
64
|
+
});
|
|
65
|
+
return m;
|
|
66
|
+
}, [barColors, allRows]);
|
|
52
67
|
const sorted = useMemo(() => sortListRows(allRows, sortBy, sortDirection, sort), [allRows, sortBy, sortDirection, sort]);
|
|
53
68
|
const scale = useMemo(() => resolveListDomain(allRows, columns.map((c) => c.column), domain, markers?.map((m) => m.value)), [allRows, columns, domain, markers]);
|
|
54
69
|
const resolvedMarkers = useMemo(() => markers?.map((m) => ({
|
|
@@ -68,17 +83,35 @@ export function BarList(props) {
|
|
|
68
83
|
// Which is also why nothing below may be the *only* signal: strip
|
|
69
84
|
// this block and a selected row still reads as selected.
|
|
70
85
|
const soleMetric = columns.length === 1;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
86
|
+
// A per-row colour makes the fill mean something, which puts it in
|
|
87
|
+
// exactly the position a multi-metric row's fill is already in: the
|
|
88
|
+
// state treatment stands down rather than trading a distinction the
|
|
89
|
+
// reader needs for one the band and rail already give them. Same
|
|
90
|
+
// rule `binColors` follows on the canvas.
|
|
91
|
+
const own = barColorOf?.get(row.key);
|
|
92
|
+
const fill = own !== undefined
|
|
93
|
+
? own
|
|
94
|
+
: state.selected && soleMetric
|
|
95
|
+
? style.highlight
|
|
96
|
+
: state.dimmed
|
|
97
|
+
? (style.dimmed ?? style.fill)
|
|
98
|
+
: style.fill;
|
|
76
99
|
// A `dimmed` token carries its own alpha (`rgba(…,0.32)`), so
|
|
77
100
|
// multiplying `opacity` on top of it would dim twice. Fall back to
|
|
78
101
|
// the raw 0.32 only when the theme names no dimmed colour.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
102
|
+
// Opacity is where a coloured bar shows its state, since its hue
|
|
103
|
+
// is spoken for. A `dimmed` THEME token carries its own alpha so
|
|
104
|
+
// multiplying on top would dim twice — but that token is not in
|
|
105
|
+
// play for a per-row colour, so the raw 0.32 applies there too.
|
|
106
|
+
const fillOpacity = own !== undefined
|
|
107
|
+
? state.dimmed
|
|
108
|
+
? style.opacity * 0.32
|
|
109
|
+
: state.selected
|
|
110
|
+
? 1
|
|
111
|
+
: style.opacity
|
|
112
|
+
: state.dimmed && style.dimmed === undefined
|
|
113
|
+
? style.opacity * 0.32
|
|
114
|
+
: style.opacity;
|
|
82
115
|
return (_jsxs("div", { "data-list-track": col.column, style: {
|
|
83
116
|
position: 'relative',
|
|
84
117
|
height: barHeight,
|