@pond-ts/charts 0.57.0 → 0.58.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/CHANGELOG.md +1070 -1
- package/dist/AreaChart.d.ts +12 -1
- package/dist/AreaChart.js +131 -13
- package/dist/BarChart.js +184 -30
- package/dist/BarList.d.ts +85 -5
- package/dist/BarList.js +25 -4
- package/dist/BoxList.d.ts +70 -3
- package/dist/BoxList.js +21 -7
- package/dist/BoxPlot.d.ts +2 -1
- package/dist/BoxPlot.js +101 -9
- package/dist/Candlestick.d.ts +13 -1
- package/dist/Candlestick.js +89 -3
- package/dist/ChartContainer.d.ts +36 -48
- package/dist/ChartContainer.js +465 -59
- package/dist/ChartRow.d.ts +9 -2
- package/dist/ChartRow.js +86 -12
- package/dist/HeatMap.d.ts +176 -0
- package/dist/HeatMap.js +344 -0
- package/dist/Layers.d.ts +5 -1
- package/dist/Layers.js +1014 -253
- package/dist/Legend.js +8 -4
- package/dist/LineChart.d.ts +18 -1
- package/dist/LineChart.js +165 -4
- package/dist/ListTable.d.ts +30 -3
- package/dist/ListTable.js +381 -23
- package/dist/ScatterChart.d.ts +3 -2
- package/dist/ScatterChart.js +68 -4
- package/dist/XAxis.js +40 -22
- package/dist/area.d.ts +34 -1
- package/dist/area.js +88 -1
- package/dist/bars.d.ts +57 -3
- package/dist/bars.js +237 -26
- package/dist/box.d.ts +2 -2
- package/dist/box.js +158 -40
- package/dist/brush.d.ts +142 -0
- package/dist/brush.js +179 -0
- package/dist/child-index.d.ts +27 -0
- package/dist/child-index.js +57 -0
- package/dist/context.d.ts +859 -33
- package/dist/cursors.d.ts +161 -0
- package/dist/cursors.js +503 -0
- package/dist/decimate.d.ts +78 -1
- package/dist/decimate.js +157 -0
- package/dist/heat.d.ts +163 -0
- package/dist/heat.js +659 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.js +22 -0
- package/dist/line.d.ts +137 -0
- package/dist/line.js +328 -0
- package/dist/ohlc.d.ts +16 -1
- package/dist/ohlc.js +93 -4
- package/dist/scatter.d.ts +17 -9
- package/dist/scatter.js +221 -33
- package/dist/select.d.ts +13 -5
- package/dist/select.js +14 -6
- package/dist/selection-fixtures.d.ts +174 -0
- package/dist/selection-fixtures.js +569 -0
- package/dist/selection-stories.d.ts +73 -0
- package/dist/selection-stories.js +301 -0
- package/dist/selectors.d.ts +316 -0
- package/dist/selectors.js +391 -0
- package/dist/span.d.ts +122 -0
- package/dist/span.js +203 -0
- package/dist/sweep.d.ts +154 -0
- package/dist/sweep.js +282 -0
- package/dist/theme.d.ts +456 -5
- package/dist/theme.js +217 -41
- package/dist/tracker.d.ts +6 -0
- package/dist/tracker.js +6 -0
- package/dist/tradingAxis.fixture.d.ts +78 -0
- package/dist/tradingAxis.fixture.js +215 -0
- package/dist/useChartLegend.js +18 -3
- package/package.json +3 -3
package/dist/HeatMap.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { useContext, useEffect, useMemo } from 'react';
|
|
2
|
+
import { ValueSeries } from 'pond-ts';
|
|
3
|
+
import { stacksFromColumns } from './data.js';
|
|
4
|
+
import { bandedColor, drawHeat, heatAt, heatValueExtent, } from './heat.js';
|
|
5
|
+
import { spansForLayer } from './span.js';
|
|
6
|
+
import { ContainerContext, LayersContext, } from './context.js';
|
|
7
|
+
import { useSlotKey } from './use-slot-key.js';
|
|
8
|
+
import { sweep2D } from './sweep.js';
|
|
9
|
+
/** Stable identity for "nothing in this set" — the resting case, so the layer
|
|
10
|
+
* doesn't rebuild its `entry` (and the canvas doesn't repaint) merely because
|
|
11
|
+
* the container handed out a fresh empty array. */
|
|
12
|
+
const NO_MARKS = [];
|
|
13
|
+
/**
|
|
14
|
+
* The cell identity of every member of `set` — the layer `id`, the bin `key`
|
|
15
|
+
* (or the stable per-bin `mark` where the series carries one) and the row
|
|
16
|
+
* `label`, which is the whole of what {@link drawHeat} matches on.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately **not** filtered to this layer's own `id` — the draw matches on
|
|
19
|
+
* it anyway, and gates its per-bin scan on whether either set names this layer
|
|
20
|
+
* at all, so a component-side filter would buy nothing and add a second place
|
|
21
|
+
* the id rule lives. What this *does* drop is the `SelectInfo` presentation
|
|
22
|
+
* fields (`value`, `color`), which the draw has no business reading.
|
|
23
|
+
*/
|
|
24
|
+
function marksOf(set) {
|
|
25
|
+
if (set.length === 0)
|
|
26
|
+
return NO_MARKS;
|
|
27
|
+
return set.map((m) => ({
|
|
28
|
+
id: m.id,
|
|
29
|
+
key: m.key,
|
|
30
|
+
label: m.label,
|
|
31
|
+
...(m.mark !== undefined ? { mark: m.mark } : {}),
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A **heat-map draw layer**: a grid of cells, bins along x and the series'
|
|
36
|
+
* columns down y, colour carrying the aggregate ([PND-HEATMAP]).
|
|
37
|
+
*
|
|
38
|
+
* ```tsx
|
|
39
|
+
* // A stripe — one column.
|
|
40
|
+
* <HeatMap series={hourly} columns={['count']} colors={ramp} id="load" />
|
|
41
|
+
*
|
|
42
|
+
* // A grid — one column per row.
|
|
43
|
+
* <HeatMap series={byCity} columns={['London', 'Paris', 'Berlin']} colors={ramp} />
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* **No reader of its own.** It builds on `stacksFromColumns`, whose output is
|
|
47
|
+
* already a heat map's data shape — bin spans, named rows, a row-major value
|
|
48
|
+
* grid. That covers all four shapes pond can express today (`TimeSeries` or
|
|
49
|
+
* `ValueSeries` × one column or many), and the stripe is simply `G === 1`, so
|
|
50
|
+
* there is one draw path rather than two.
|
|
51
|
+
*
|
|
52
|
+
* **The readout is the point.** A cell carries its value, so hover and click
|
|
53
|
+
* report it and the readout pill takes the cell's own colour. The bar-based
|
|
54
|
+
* workaround this replaces cannot: its bars are a constant-height column
|
|
55
|
+
* carrying no value, so the number has to be looked up out-of-band.
|
|
56
|
+
*
|
|
57
|
+
* **Styling.** Colour is data and comes from `colors`, not the theme. Geometry
|
|
58
|
+
* and the selected-cell treatment are borrowed from
|
|
59
|
+
* `theme.bar[as] ?? theme.bar.default` rather than a new `theme.heat` slot:
|
|
60
|
+
* `ChartTheme`'s slots are required, so adding one is breaking for every custom
|
|
61
|
+
* theme, and the M5 "theme tokens optional-with-default" gate has to land
|
|
62
|
+
* first. Borrowing defers that decision instead of pre-empting it.
|
|
63
|
+
*
|
|
64
|
+
* **Pair it with `<ChartContainer cursor="none">`.** The container's default is
|
|
65
|
+
* the shared vertical line, and on a grid that is a *second, weaker* cursor
|
|
66
|
+
* competing with the one that already works: the cell under the pointer takes an
|
|
67
|
+
* outline, which says both axes at once. The line says only x, and a heat map's
|
|
68
|
+
* x position is rarely the question. The pointer's own crosshair shape plus the
|
|
69
|
+
* cell outline is the whole affordance.
|
|
70
|
+
*
|
|
71
|
+
* **Not built:** a grouped two-level x axis, and cell value labels. The former
|
|
72
|
+
* is axis work that would serve bars equally; the latter is small and
|
|
73
|
+
* independent.
|
|
74
|
+
*/
|
|
75
|
+
export function HeatMap({ series, columns, colors, domain, orientation = 'vertical', as: semantic, axis, gap = 0, scale = 'linear', noData = 'blank', decimate = true, id, index = 0, }) {
|
|
76
|
+
const container = useContext(ContainerContext);
|
|
77
|
+
if (container === null) {
|
|
78
|
+
throw new Error('<HeatMap> must be rendered inside a <ChartContainer>');
|
|
79
|
+
}
|
|
80
|
+
const layers = useContext(LayersContext);
|
|
81
|
+
if (layers === null) {
|
|
82
|
+
throw new Error('<HeatMap> must be rendered inside a <Layers>');
|
|
83
|
+
}
|
|
84
|
+
if (columns.length === 0) {
|
|
85
|
+
throw new Error('<HeatMap> needs at least one column (one row per column)');
|
|
86
|
+
}
|
|
87
|
+
// `columns`, `colors` and `domain` are **array** props, and the natural way to
|
|
88
|
+
// write every one of them is a fresh array per render — a JSX literal, a
|
|
89
|
+
// `.map()`, or a theme hook like the docs site's `useSequentialRamp()`. Keyed
|
|
90
|
+
// by identity they would rebuild the layer `entry` every render, hence a
|
|
91
|
+
// `registerLayer` every render: a repaint treadmill, not a noisy warning. So
|
|
92
|
+
// memoize on **content**, exactly as `<BarChart thresholds>` does. The joiner
|
|
93
|
+
// is NUL rather than a comma because a column name may contain a comma, and
|
|
94
|
+
// `['a,b']` must not key the same as `['a', 'b']`.
|
|
95
|
+
const columnsKey = columns.join('\u0000');
|
|
96
|
+
const colorsKey = colors.join('\u0000');
|
|
97
|
+
const domainKey = domain === undefined ? '' : `${domain[0]}\u0000${domain[1]}`;
|
|
98
|
+
const ss = useMemo(() => stacksFromColumns(series, columns), [series, columnsKey]);
|
|
99
|
+
const { bar } = container.theme;
|
|
100
|
+
const base = (semantic !== undefined ? bar[semantic] : undefined) ?? bar.default;
|
|
101
|
+
// The geometry comes from the BAR slot (a cell is a bar's slot with colour
|
|
102
|
+
// instead of height); the interaction states come from `theme.heat`, which
|
|
103
|
+
// exists because a bar's fill is free and a cell's fill is the datum — see
|
|
104
|
+
// `HeatStates`. Absent, the pre-states treatment is unchanged.
|
|
105
|
+
const heatStates = container.theme.heat;
|
|
106
|
+
const states = (semantic !== undefined ? heatStates?.[semantic] : undefined) ??
|
|
107
|
+
heatStates?.default;
|
|
108
|
+
const style = useMemo(() => ({
|
|
109
|
+
opacity: base.opacity,
|
|
110
|
+
highlight: base.highlight,
|
|
111
|
+
outlineWidth: base.outlineWidth,
|
|
112
|
+
gap,
|
|
113
|
+
minWidth: base.minWidth,
|
|
114
|
+
gridColor: container.theme.axis.grid,
|
|
115
|
+
...(states !== undefined ? { states } : {}),
|
|
116
|
+
}), [base, gap, container.theme.axis.grid, states]);
|
|
117
|
+
// One colour domain across the whole grid, so rows are comparable.
|
|
118
|
+
const [lo, hi] = useMemo(() => domain ?? heatValueExtent(ss) ?? [0, 1], [domainKey, ss]);
|
|
119
|
+
const G = ss.groups.length;
|
|
120
|
+
const vertical = orientation === 'vertical';
|
|
121
|
+
// Colour is a function of the **value**, which is the layer's whole model —
|
|
122
|
+
// so the closure takes one. It also lets a decimated pixel column, which has
|
|
123
|
+
// no source `(b, g)`, be coloured by the same ramp.
|
|
124
|
+
const colorOf = useMemo(() => (value) => bandedColor(value, colors, lo, hi, scale), [colorsKey, lo, hi, scale]);
|
|
125
|
+
const selected = container.selected;
|
|
126
|
+
const hoveredMark = container.hovered;
|
|
127
|
+
// Both channels are **sets** — `selected` since [PND-MULTISEL], `hovered`
|
|
128
|
+
// since RFC A4.3 — and both reach `drawHeat` whole, which lights every cell a
|
|
129
|
+
// member names. Narrowed here only from `SelectInfo` down to the cell identity
|
|
130
|
+
// (`id` + `key`/`mark` + row `label`), so `heat.ts` stays free of the
|
|
131
|
+
// selection's presentation fields exactly as it is free of the theme.
|
|
132
|
+
const selection = useMemo(() => marksOf(selected), [selected]);
|
|
133
|
+
const hover = useMemo(() => marksOf(hoveredMark), [hoveredMark]);
|
|
134
|
+
// The selection's span entries, narrowed to this layer (interaction RFC
|
|
135
|
+
// A5.2). A heat map's labels vary per cell (the row names — the ordinal
|
|
136
|
+
// second dimension a span addresses via `rows`, RFC A5.3), so no label is
|
|
137
|
+
// passed and the `rows` channel rides through for `drawHeat` to test per
|
|
138
|
+
// cell. Reference-stable when empty, like the mark memos above.
|
|
139
|
+
const layerSpans = useMemo(() => spansForLayer(container.selectedSpans, id), [container.selectedSpans, id]);
|
|
140
|
+
const entry = useMemo(() => ({
|
|
141
|
+
layer: {
|
|
142
|
+
as: semantic,
|
|
143
|
+
// Inferred, exactly as BarChart does it — no axis-kind prop.
|
|
144
|
+
// Horizontal moves the bins to y, so x becomes the categories the
|
|
145
|
+
// columns name — which is the container's `'category'` kind, exactly as
|
|
146
|
+
// a categorical `<BarChart>` reports it.
|
|
147
|
+
xKind: vertical
|
|
148
|
+
? series instanceof ValueSeries
|
|
149
|
+
? 'value'
|
|
150
|
+
: 'time'
|
|
151
|
+
: 'category',
|
|
152
|
+
xExtent: () => vertical
|
|
153
|
+
? ss.length === 0
|
|
154
|
+
? null
|
|
155
|
+
: [ss.begin[0], ss.end[ss.length - 1]]
|
|
156
|
+
: [0, G],
|
|
157
|
+
yExtent: () => vertical
|
|
158
|
+
? [0, G]
|
|
159
|
+
: ss.length === 0
|
|
160
|
+
? null
|
|
161
|
+
: [ss.begin[0], ss.end[ss.length - 1]],
|
|
162
|
+
// Unit slots, one per column, labelled at each centre — on whichever
|
|
163
|
+
// axis they landed. `binCategories` is the y-axis channel and
|
|
164
|
+
// `xCategories` the x-axis one ([PND-HCAT]).
|
|
165
|
+
...(vertical
|
|
166
|
+
? { binCategories: () => ss.groups }
|
|
167
|
+
: { xCategories: () => ss.groups }),
|
|
168
|
+
// The x-scrub tracker samples along x, which is the bin axis only when
|
|
169
|
+
// vertical. A horizontal grid answers through `onHover` / `onSelect`
|
|
170
|
+
// instead, which resolve both axes — the same split the 2-D readout
|
|
171
|
+
// already forced.
|
|
172
|
+
sampleAt: (x) => {
|
|
173
|
+
if (!vertical)
|
|
174
|
+
return [];
|
|
175
|
+
// Every row's value at the cursor — the whole column of the grid,
|
|
176
|
+
// which is what an off-chart readout wants from a heat map.
|
|
177
|
+
for (let b = 0; b < ss.length; b += 1) {
|
|
178
|
+
if (x < ss.begin[b] || x > ss.end[b])
|
|
179
|
+
continue;
|
|
180
|
+
const out = [];
|
|
181
|
+
for (let g = 0; g < G; g += 1) {
|
|
182
|
+
const v = ss.values[b * G + g];
|
|
183
|
+
if (!Number.isFinite(v))
|
|
184
|
+
continue;
|
|
185
|
+
out.push({
|
|
186
|
+
x: (ss.begin[b] + ss.end[b]) / 2,
|
|
187
|
+
// `value` is where the cursor *draws* — `yScale(value)` — so
|
|
188
|
+
// it must be a y coordinate, and for a cell that is its row's
|
|
189
|
+
// centre, not its number. The number rides `readout`, which
|
|
190
|
+
// an off-chart consumer shows as `readout ?? value`. Without
|
|
191
|
+
// the split the dot would be placed at `yScale(anomaly)` on a
|
|
192
|
+
// unit-slot axis and land outside the plot entirely.
|
|
193
|
+
value: g + 0.5,
|
|
194
|
+
readout: v,
|
|
195
|
+
color: colorOf(v) ?? style.highlight,
|
|
196
|
+
label: ss.groups[g],
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
return [];
|
|
202
|
+
},
|
|
203
|
+
...(id === undefined
|
|
204
|
+
? {}
|
|
205
|
+
: {
|
|
206
|
+
hitTest: (px, py, xScale, yScale) => {
|
|
207
|
+
const hit = heatAt(ss, px, py, xScale, yScale, style.gap, style.minWidth, orientation);
|
|
208
|
+
if (hit === null)
|
|
209
|
+
return null;
|
|
210
|
+
const [b, g, begin, name, value] = hit;
|
|
211
|
+
const mark = ss.marks?.[b];
|
|
212
|
+
return {
|
|
213
|
+
id,
|
|
214
|
+
key: begin,
|
|
215
|
+
value,
|
|
216
|
+
color: colorOf(value) ?? style.highlight,
|
|
217
|
+
label: name,
|
|
218
|
+
...(mark !== undefined ? { mark } : {}),
|
|
219
|
+
};
|
|
220
|
+
},
|
|
221
|
+
/**
|
|
222
|
+
* The **snapped rect** ([PND-INTERACT2D]). Both dimensions snap:
|
|
223
|
+
* x to whole bin columns (`sweep2D`'s cut, as every column mark
|
|
224
|
+
* does) and y **outward to whole row slots** — a vertical heat
|
|
225
|
+
* map's rows own the unit intervals `[g, g+1)` of its value axis
|
|
226
|
+
* (see `yExtent`), so a window is floored and ceiled onto them.
|
|
227
|
+
*
|
|
228
|
+
* Snapping both is what makes the selection a contiguous
|
|
229
|
+
* rectangle of cells, which in turn is why the region can carry
|
|
230
|
+
* **one** perimeter rather than a border per cell.
|
|
231
|
+
*/
|
|
232
|
+
// A cell owns a position, not a column: the sweep is a rect, and
|
|
233
|
+
// the resting cursor is the small crosshair rather than a band.
|
|
234
|
+
//
|
|
235
|
+
// Gated on exactly what `beginSweep` gates on. `sweepsRect` is
|
|
236
|
+
// read at REST, where there is no session to ask, so declaring
|
|
237
|
+
// it unconditionally made a HORIZONTAL heat map suppress its
|
|
238
|
+
// row's cursor and paint a resting `+` for a rect gesture that
|
|
239
|
+
// can never start — `beginSweep` returns `null` there.
|
|
240
|
+
sweepsRect: vertical && ss.length > 0 && G > 0,
|
|
241
|
+
beginSweep: () => {
|
|
242
|
+
if (!vertical || ss.length === 0 || G === 0)
|
|
243
|
+
return null;
|
|
244
|
+
/** The window's covering row-slot run, snapped outward. */
|
|
245
|
+
const rowRun = (y0, y1) => {
|
|
246
|
+
const g0 = Math.max(0, Math.floor(y0));
|
|
247
|
+
const g1 = Math.min(G, Math.ceil(y1));
|
|
248
|
+
return [g0, g1 > g0 ? g1 : g0];
|
|
249
|
+
};
|
|
250
|
+
return sweep2D({
|
|
251
|
+
id,
|
|
252
|
+
begin: ss.begin,
|
|
253
|
+
end: ss.end,
|
|
254
|
+
length: ss.length,
|
|
255
|
+
spanFrom: 'bins',
|
|
256
|
+
materialize: (lo, hi, y0, y1) => {
|
|
257
|
+
const [g0, g1] = rowRun(y0, y1);
|
|
258
|
+
const out = [];
|
|
259
|
+
for (let b = lo; b < hi; b += 1) {
|
|
260
|
+
const mark = ss.marks?.[b];
|
|
261
|
+
for (let g = g0; g < g1; g += 1) {
|
|
262
|
+
const v = ss.values[b * G + g];
|
|
263
|
+
// A gap cell draws nothing and owns no membership —
|
|
264
|
+
// the rule `hitTest` already applies.
|
|
265
|
+
if (!Number.isFinite(v))
|
|
266
|
+
continue;
|
|
267
|
+
out.push({
|
|
268
|
+
id,
|
|
269
|
+
key: ss.begin[b],
|
|
270
|
+
value: v,
|
|
271
|
+
color: colorOf(v) ?? style.highlight,
|
|
272
|
+
label: ss.groups[g],
|
|
273
|
+
...(mark !== undefined ? { mark } : {}),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return out;
|
|
278
|
+
},
|
|
279
|
+
// The brush draws THIS, not the pointer rectangle: the cut
|
|
280
|
+
// snaps to whole bins and whole rows, so a raw rect would
|
|
281
|
+
// promise a different set than the release delivers — and
|
|
282
|
+
// it disagrees most visibly at the moment the user is
|
|
283
|
+
// deciding where to let go.
|
|
284
|
+
snap: (lo, hi, y0, y1) => {
|
|
285
|
+
const [g0, g1] = rowRun(y0, y1);
|
|
286
|
+
return g1 > g0
|
|
287
|
+
? { x: [ss.begin[lo], ss.end[hi - 1]], y: [g0, g1] }
|
|
288
|
+
: null;
|
|
289
|
+
},
|
|
290
|
+
// `rows` names the rows rather than numbering slots, so a
|
|
291
|
+
// committed selection survives a row reorder (RFC A5.3).
|
|
292
|
+
channels: (_hits, y0, y1) => {
|
|
293
|
+
const [g0, g1] = rowRun(y0, y1);
|
|
294
|
+
return { rows: ss.groups.slice(g0, g1) };
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
}),
|
|
299
|
+
draw: (ctx, xScale, yScale) => drawHeat(ctx, ss, xScale, yScale, style, colorOf, id,
|
|
300
|
+
// Both sets whole. Passing `selection[0]` here quietly showed one
|
|
301
|
+
// outline for a three-cell selection — the memos above were plural
|
|
302
|
+
// long before the draw was.
|
|
303
|
+
selection, hover, decimate, orientation, noData, layerSpans),
|
|
304
|
+
},
|
|
305
|
+
axisId: axis,
|
|
306
|
+
index,
|
|
307
|
+
}), [
|
|
308
|
+
ss,
|
|
309
|
+
G,
|
|
310
|
+
style,
|
|
311
|
+
colorOf,
|
|
312
|
+
decimate,
|
|
313
|
+
orientation,
|
|
314
|
+
noData,
|
|
315
|
+
vertical,
|
|
316
|
+
semantic,
|
|
317
|
+
series,
|
|
318
|
+
id,
|
|
319
|
+
axis,
|
|
320
|
+
index,
|
|
321
|
+
selection,
|
|
322
|
+
hover,
|
|
323
|
+
layerSpans,
|
|
324
|
+
]);
|
|
325
|
+
const slot = useSlotKey();
|
|
326
|
+
useEffect(() => () => layers.unregisterLayer(slot), [layers, slot]);
|
|
327
|
+
useEffect(() => {
|
|
328
|
+
layers.registerLayer(slot, entry);
|
|
329
|
+
}, [layers, slot, entry]);
|
|
330
|
+
const { registerTrackerSource, unregisterTrackerSource } = container;
|
|
331
|
+
useEffect(() => () => unregisterTrackerSource(slot), [unregisterTrackerSource, slot]);
|
|
332
|
+
useEffect(() => {
|
|
333
|
+
registerTrackerSource(slot, entry.layer);
|
|
334
|
+
}, [registerTrackerSource, slot, entry.layer]);
|
|
335
|
+
const { registerSelectable, unregisterSelectable } = container;
|
|
336
|
+
useEffect(() => {
|
|
337
|
+
if (id === undefined)
|
|
338
|
+
return;
|
|
339
|
+
registerSelectable(slot);
|
|
340
|
+
return () => unregisterSelectable(slot);
|
|
341
|
+
}, [registerSelectable, unregisterSelectable, slot, id]);
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=HeatMap.js.map
|
package/dist/Layers.d.ts
CHANGED
|
@@ -16,7 +16,11 @@ export interface LayersProps {
|
|
|
16
16
|
* others slots into place, not onto the top), and each layer keeps a stable,
|
|
17
17
|
* id-keyed slot so a series/style update holds its position (no jump to the
|
|
18
18
|
* front — the trap that bites live charts). Draw layers must be **direct
|
|
19
|
-
* children** of `<Layers>` for the index to reach them
|
|
19
|
+
* children** of `<Layers>` for the index to reach them — to group them
|
|
20
|
+
* conditionally, return a **keyed array**, not a `<>…</>`: a fragment takes no
|
|
21
|
+
* props, so the index stops there and the layers inside it all register at 0
|
|
22
|
+
* (dev warns about this, because a stable sort makes the resulting tie look
|
|
23
|
+
* correct until mount order and declaration order disagree).
|
|
20
24
|
*/
|
|
21
25
|
export declare function Layers({ children }: LayersProps): import("react/jsx-runtime").JSX.Element;
|
|
22
26
|
//# sourceMappingURL=Layers.d.ts.map
|