@pond-ts/charts 0.69.0 → 0.71.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 (46) hide show
  1. package/AGENTS.md +3 -1
  2. package/API.md +55 -56
  3. package/CHANGELOG.md +177 -1
  4. package/dist/AreaChart.d.ts +30 -22
  5. package/dist/AreaChart.js +37 -22
  6. package/dist/BandChart.d.ts +20 -1
  7. package/dist/BandChart.js +18 -2
  8. package/dist/BoxPlot.js +5 -3
  9. package/dist/Candlestick.d.ts +3 -3
  10. package/dist/Candlestick.js +5 -5
  11. package/dist/ChartContainer.d.ts +8 -149
  12. package/dist/ChartContainer.js +68 -111
  13. package/dist/ChartRow.d.ts +1 -12
  14. package/dist/ChartRow.js +15 -30
  15. package/dist/HeatMap.d.ts +3 -3
  16. package/dist/HeatMap.js +3 -3
  17. package/dist/Layers.js +84 -34
  18. package/dist/XAxis.js +1 -0
  19. package/dist/area.d.ts +6 -5
  20. package/dist/area.js +13 -6
  21. package/dist/axis-events.d.ts +4 -4
  22. package/dist/band.d.ts +10 -2
  23. package/dist/band.js +38 -10
  24. package/dist/brush.d.ts +13 -21
  25. package/dist/brush.js +22 -36
  26. package/dist/context.d.ts +81 -96
  27. package/dist/cursors.d.ts +81 -51
  28. package/dist/cursors.js +164 -127
  29. package/dist/decimate.d.ts +10 -1
  30. package/dist/decimate.js +51 -10
  31. package/dist/elapsed.d.ts +1 -1
  32. package/dist/elapsed.js +1 -1
  33. package/dist/format.d.ts +2 -1
  34. package/dist/index.d.ts +1 -1
  35. package/dist/selection-fixtures.d.ts +4 -7
  36. package/dist/selection-fixtures.js +0 -9
  37. package/dist/selection-stories.d.ts +4 -6
  38. package/dist/selection-stories.js +4 -4
  39. package/dist/selectors.d.ts +2 -3
  40. package/dist/selectors.js +2 -3
  41. package/dist/tracker.d.ts +10 -28
  42. package/dist/tracker.js +17 -40
  43. package/dist/tradingAxis.fixture.d.ts +19 -0
  44. package/dist/tradingAxis.fixture.js +24 -0
  45. package/dist/tradingTimeScale.d.ts +2 -2
  46. package/package.json +3 -3
@@ -6,12 +6,12 @@ import { scaleBand } from './bandScale.js';
6
6
  import { scaleElapsed } from './elapsed.js';
7
7
  import { Sequence, TimeZone } from 'pond-ts';
8
8
  import { ContainerContext, CursorContext, } from './context.js';
9
- import { LegacyCursor, legacyCursorWarning, presetNameFor, warnOnDuplicateGestureOwners, } from './cursors.js';
9
+ import { warnOnDuplicateGestureOwners } from './cursors.js';
10
10
  import { effectiveSelectorEntries, resolveControlledHovered, resolveControlledSelected, selectorEntryEqual, warnInertClick, } from './selectors.js';
11
11
  import { isDev } from './dev.js';
12
12
  import { maxSlotWidths, sum } from './slots.js';
13
13
  import { computeLabelLanes } from './annotations.js';
14
- import { resolveCursorX, DEFAULT_CURSOR_MODE } from './tracker.js';
14
+ import { resolveCursorX } from './tracker.js';
15
15
  import { clampToBounds } from './viewport.js';
16
16
  import { resolveAxisFormat, resolveTimeFormat, } from './format.js';
17
17
  import { TimeAxis } from './TimeAxis.js';
@@ -198,14 +198,7 @@ function AutoSizeContainer(props) {
198
198
  * pass; a chart legitimately gated this long is not painting anyway. */
199
199
  const ZERO_SIZE_WARNING_MS = 600;
200
200
  /** {@link ChartContainer} with its width resolved to a concrete pixel number. */
201
- function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidth, bandAlign = 'start', width, height, rowGap = 0, showAxis = true, trackerPosition, onTrackerChanged, onDrawStats, panZoom = false, axisPanZoom = false, bounds, onTimeRangeChange, minDuration = 1, cursor: cursorProp, cursorSequence: cursorSequenceProp, onRegionSelect, regionSelectModifier, cursorTime: cursorTimeProp, crosshairSnap: crosshairSnapProp, editAnnotations = false, creating = null, onCreate, onSelectAnnotation, onHoverAnnotation, onEditAnnotation, snap = true, timeFormat, cursorFormat: cursorFormatProp, origin, theme, discontinuities, calendar, timeZone: timeZoneProp, spacing, xScale: xScaleKind = 'linear', grid = true, sessionDividers = 'none', children, }) {
202
- // ── Legacy cursor props (deprecated) ───────────────────────────────────────
203
- // The string surface keeps working for one minor: the resolved mode is
204
- // synthesized into the equivalent mounted preset below (`<LegacyCursor>`),
205
- // and a dev warning names the replacement whenever any of the props is
206
- // *explicitly* set (never on the defaults). Mounted cursor components in the
207
- // same scope override the shim. See docs/rfcs/interaction.md §9 / A4.4.
208
- const cursor = cursorProp ?? DEFAULT_CURSOR_MODE;
201
+ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidth, bandAlign = 'start', width, height, rowGap = 0, showAxis = true, trackerPosition, onTrackerChanged, onDrawStats, panZoom = false, axisPanZoom = false, bounds, onTimeRangeChange, minDuration = 1, editAnnotations = false, creating = null, onCreate, onSelectAnnotation, onHoverAnnotation, onEditAnnotation, snap = true, timeFormat, origin, theme, discontinuities, calendar, timeZone: timeZoneProp, spacing, xScale: xScaleKind = 'linear', grid = true, sessionDividers = 'none', children, }) {
209
202
  // [PND-HEIGHT] Whether this container owns vertical layout (see the
210
203
  // `height` prop). Carried on the frame so a `<ChartRow flex>` can tell a
211
204
  // home that can size it from one that never will.
@@ -223,43 +216,8 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
223
216
  const declaredCategories = useMemo(() => categoriesProp === undefined ? null : [...categoriesProp],
224
217
  // eslint-disable-next-line react-hooks/exhaustive-deps -- content identity
225
218
  [categoriesKey]);
226
- const cursorTime = cursorTimeProp ?? false;
227
- const crosshairSnap = crosshairSnapProp ?? true;
228
- const warnedLegacyRef = useRef(false);
229
- useEffect(() => {
230
- if (!isDev || warnedLegacyRef.current)
231
- return;
232
- const legacy = [];
233
- if (cursorProp !== undefined)
234
- legacy.push(`cursor="${cursorProp}" → mount ${presetNameFor(cursorProp)}`);
235
- if (crosshairSnapProp !== undefined)
236
- legacy.push('crosshairSnap → <CrosshairCursor snap>');
237
- if (cursorTimeProp !== undefined)
238
- legacy.push('cursorTime → showTime on the mounted cursor');
239
- if (cursorFormatProp !== undefined)
240
- legacy.push('cursorFormat → format on <CrosshairCursor>');
241
- if (cursorSequenceProp !== undefined)
242
- legacy.push('cursorSequence → <RangeCursor sequence>');
243
- if (onRegionSelect !== undefined)
244
- legacy.push('onRegionSelect → <RangeCursor onDragRelease> (the payload becomes ' +
245
- '{ x: [lo, hi] })');
246
- if (regionSelectModifier !== undefined)
247
- legacy.push('regionSelectModifier → <RangeCursor dragModifier>');
248
- if (legacy.length === 0)
249
- return;
250
- warnedLegacyRef.current = true;
251
- console.warn(legacyCursorWarning(legacy));
252
- }, [
253
- cursorProp,
254
- crosshairSnapProp,
255
- cursorTimeProp,
256
- cursorFormatProp,
257
- cursorSequenceProp,
258
- onRegionSelect,
259
- regionSelectModifier,
260
- ]);
261
219
  // Mounted-cursor registry ({@link ContainerFrame.registerCursor}): the
262
- // presets (and the legacy shim) register their specs here; rows and
220
+ // presets register their specs here; rows and
263
221
  // `<XAxis>` render the effective set. Same per-instance-slot discipline as
264
222
  // the tracker sources; register is idempotent under reference equality (the
265
223
  // presets memoize their entries on props).
@@ -282,16 +240,12 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
282
240
  useEffect(() => {
283
241
  warnOnDuplicateGestureOwners(cursors, warnedGestureRef);
284
242
  }, [cursors]);
285
- // The registered cursors' resolution inputs, folded into the legacy
286
- // channels: a mounted `<CrosshairCursor format>` feeds the shared readout
287
- // channel exactly where `cursorFormat` fed it. First **component-mounted**
288
- // entry wins (the shim registers before the children mount, so a bare
289
- // first-wins would let the legacy synthesis shadow a real mount); the
290
- // legacy prop is the fallback during the window. (`sequence` resolves the
243
+ // The registered cursors' resolution inputs: a mounted cursor's `format`
244
+ // feeds the shared readout channel (the x pill, marker indicators,
245
+ // annotation auto-labels). First mounted wins. (`sequence` resolves the
291
246
  // same way, below the selector registry — a `<MultiSelector sequence>`
292
247
  // feeds the same channel.)
293
- const cursorFormat = useMemo(() => cursors.find((e) => !e.legacy && e.format !== undefined)?.format ??
294
- cursorFormatProp, [cursors, cursorFormatProp]);
248
+ const cursorFormat = useMemo(() => cursors.find((e) => e.format !== undefined)?.format, [cursors]);
295
249
  // Which axes the gestures own. **Pan follows zoom's degrees of freedom**: an
296
250
  // axis that can be zoomed can be panned, because a zoomed axis shows less than
297
251
  // all of itself and the reader needs to reach the rest. `'pan'` is the one
@@ -445,7 +399,7 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
445
399
  setSelectableKeys(next);
446
400
  }, []);
447
401
  // Mounted-selector registry ({@link ContainerFrame.registerSelector}):
448
- // `<Selector>` — and the legacy shim below — register here, and **the
402
+ // `<Selector>` / `<MultiSelector>` register here, and **the
449
403
  // registration is what enables a plot click** (interaction RFC §7.1). Same
450
404
  // per-instance-slot discipline as the cursors/tracker sources. Mirrored to a
451
405
  // ref because `select` / `setHovered` are `[]`-stable callbacks that must not
@@ -477,15 +431,13 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
477
431
  }, []);
478
432
  const selectors = useMemo(() => Array.from(selectorMap.values()), [selectorMap]);
479
433
  const selectorsRef = useRef(selectors);
480
- // The shared snap-bucket sequence, folded into the legacy channel exactly as
481
- // `cursorFormat` is above: a component-mounted `<RangeCursor sequence>`
482
- // wins, then a mounted `<MultiSelector sequence>` (its sweep extends bucket
483
- // by bucket over the same realized buckets — one channel, so the band and
484
- // the sweep can never snap differently), then the legacy shim / prop.
485
- const cursorSequence = useMemo(() => cursors.find((e) => !e.legacy && e.sequence !== undefined)?.sequence ??
486
- selectors.find((e) => e.sequence !== undefined)?.sequence ??
487
- cursors.find((e) => e.sequence !== undefined)?.sequence ??
488
- cursorSequenceProp, [cursors, selectors, cursorSequenceProp]);
434
+ // The shared snap-bucket sequence, resolved like `cursorFormat` above: a
435
+ // mounted `<RangeCursor sequence>` wins, then a mounted `<MultiSelector
436
+ // sequence>` (its sweep extends bucket by bucket over the same realized
437
+ // buckets — one channel, so the band and the sweep can never snap
438
+ // differently).
439
+ const cursorSequence = useMemo(() => cursors.find((e) => e.sequence !== undefined)?.sequence ??
440
+ selectors.find((e) => e.sequence !== undefined)?.sequence, [cursors, selectors]);
489
441
  // Annotations register here so the container can do what a mark can't in
490
442
  // isolation: draw its guide line across other rows, order regions, serve snap
491
443
  // targets. Keyed by per-instance slot key (same discipline as the sources).
@@ -1201,10 +1153,10 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1201
1153
  // briefly stale until the next pointer move — rare, and the bounds check below
1202
1154
  // hides an out-of-plot crosshair meanwhile.
1203
1155
  const cursorX = resolveCursorX(trackerPosition, hoverX, xScale);
1204
- // `cursor="region"` snap buckets — the intervals the band snaps to (and a drag
1156
+ // `<RangeCursor>` snap buckets — the intervals the band snaps to (and a drag
1205
1157
  // extends bucket by bucket over). Two sources, in precedence order:
1206
1158
  //
1207
- // 1. **An explicit `cursorSequence`** (time axis only): realized over the view
1159
+ // 1. **An explicit `sequence`** (time axis only): realized over the view
1208
1160
  // (a `Sequence` → `.bounded`; a `BoundedSequence` used as-is). A `Sequence`
1209
1161
  // bucket is a *time* interval, so it's gated to a time axis — realizing time
1210
1162
  // buckets over a value domain is meaningless (it would shade the whole plot).
@@ -1231,9 +1183,9 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1231
1183
  // or a time-axis histogram with no explicit sequence). `binIntervals` is only
1232
1184
  // published by a vertical bar layer, so this is a no-op for
1233
1185
  // line/area/scatter rows. On a **category** axis the bins are the unit
1234
- // slots `[i, i+1)`: the region cursor never reads them (its band gates on
1235
- // a continuous axis), but the `<MultiSelector>` sweep's band snaps over
1236
- // them so it runs slot-edge to slot-edge — the band scale's `invert`
1186
+ // slots `[i, i+1)`: the `<RangeCursor>` band shades the slot under the
1187
+ // pointer ([PND-ORDCURSOR]), and the `<MultiSelector>` sweep's band snaps
1188
+ // over them so it runs slot-edge to slot-edge — the band scale's `invert`
1237
1189
  // returns slot *centres*, and a centre-to-centre band disagreed with the
1238
1190
  // snapped-outward span the release commits (RFC A7.6's edge rule).
1239
1191
  //
@@ -1294,6 +1246,25 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1294
1246
  'axis; key the data on the quantity itself (a `ValueSeries`) to get a ' +
1295
1247
  'value axis you can scale.');
1296
1248
  }
1249
+ // [PND-ORDCURSOR] A `<RangeCursor onDragRelease>` on a category axis draws
1250
+ // its slot band but never starts a drag (`resolveRangeDrag`): the callback
1251
+ // would silently never fire, so say so once. Same `sources.size` guard as
1252
+ // above — the kind is 'time' until the layers register.
1253
+ const rangeDragOnCategory = resolvedKind === 'category' &&
1254
+ sources.size > 0 &&
1255
+ cursors.some((e) => e.onDragRelease !== undefined && e.enableDrag !== false);
1256
+ const warnedRangeDragOnCategoryRef = useRef(false);
1257
+ useEffect(() => {
1258
+ if (!isDev || !rangeDragOnCategory)
1259
+ return;
1260
+ if (warnedRangeDragOnCategoryRef.current)
1261
+ return;
1262
+ warnedRangeDragOnCategoryRef.current = true;
1263
+ console.warn('[pond-charts] <RangeCursor onDragRelease> is mounted on a category x ' +
1264
+ 'axis, where the range drag is off: the band shades the slot under the ' +
1265
+ 'pointer, but `onDragRelease` never fires. To drag across bars and get ' +
1266
+ 'them back, mount a <MultiSelector> instead.');
1267
+ }, [rangeDragOnCategory]);
1297
1268
  const xIsLog = ((s) => {
1298
1269
  const probe = s;
1299
1270
  return (typeof probe.base === 'function' || typeof probe.constant === 'function');
@@ -1342,15 +1313,12 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1342
1313
  rowGap,
1343
1314
  setHoverX,
1344
1315
  setHoverY,
1345
- crosshairSnap,
1346
1316
  cursorBuckets,
1347
1317
  regionAnchor,
1348
1318
  previewSpans,
1349
1319
  setPreviewSpans,
1350
1320
  setRegionAnchor,
1351
- onRegionSelect,
1352
1321
  reportDrawStats,
1353
- regionSelectModifier,
1354
1322
  draggingKey,
1355
1323
  setDragging,
1356
1324
  selected: selectedValue,
@@ -1358,8 +1326,6 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1358
1326
  select,
1359
1327
  hovered: hoveredValue,
1360
1328
  setHovered,
1361
- cursor,
1362
- cursorTime,
1363
1329
  editAnnotations,
1364
1330
  creating,
1365
1331
  snap,
@@ -1428,15 +1394,12 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1428
1394
  rightGutter,
1429
1395
  rowGap,
1430
1396
  setHoverY,
1431
- crosshairSnap,
1432
1397
  cursorBuckets,
1433
1398
  regionAnchor,
1434
1399
  previewSpans,
1435
1400
  setPreviewSpans,
1436
1401
  setRegionAnchor,
1437
- onRegionSelect,
1438
1402
  reportDrawStats,
1439
- regionSelectModifier,
1440
1403
  draggingKey,
1441
1404
  setDragging,
1442
1405
  selectedValue,
@@ -1444,8 +1407,6 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1444
1407
  select,
1445
1408
  hoveredValue,
1446
1409
  setHovered,
1447
- cursor,
1448
- cursorTime,
1449
1410
  editAnnotations,
1450
1411
  creating,
1451
1412
  snap,
@@ -1499,37 +1460,33 @@ function ResolvedChartContainer({ range, categories: categoriesProp, maxBandWidt
1499
1460
  registerRow,
1500
1461
  firstRowKey,
1501
1462
  ]);
1502
- return (_jsx(ContainerContext.Provider, { value: frame, children: _jsxs(CursorContext.Provider, { value: cursorFrame, children: [_jsx(LegacyCursor, { mode: cursor, showTime: cursorTime, snap: crosshairSnap, sequence: cursorSequenceProp,
1503
- // The 'line' default nobody asked for is IMPLICIT — the one cursor a
1504
- // <MultiSelector>'s resting block preview may replace with the
1505
- // brush band. An explicit `cursor` prop (any mode) still wins.
1506
- implicit: cursorProp === undefined }), _jsxs("div", { style: {
1507
- width: `${width}px`,
1508
- // [PND-HEIGHT] A managed height makes the outer box a flex
1509
- // column: the rows block below flexes, the axis strip keeps its
1510
- // natural height at the bottom, and CSS subtracts one from the
1511
- // other. That subtraction being layout rather than arithmetic is
1512
- // the feature — the strip's height varies with label, font size,
1513
- // calendar bands and pill lanes, so no constant is correct.
1514
- ...(height !== undefined
1515
- ? {
1516
- height: `${height}px`,
1517
- display: 'flex',
1518
- flexDirection: 'column',
1519
- }
1520
- : {}),
1521
- }, children: [_jsx("div", { style: {
1522
- display: 'flex',
1523
- flexDirection: 'column',
1524
- gap: `${rowGap}px`,
1525
- // The positioned ancestor for overlay chrome (`<Legend>`): the
1526
- // card anchors to the rows block, never the axis strip below.
1527
- position: 'relative',
1528
- // The rows block takes what the axis strip leaves. `minHeight:
1529
- // 0` lets it shrink below its content — without it a flex
1530
- // child's floor is its content and nothing can ever get
1531
- // smaller.
1532
- ...(height !== undefined ? { flex: '1 1 0%', minHeight: 0 } : {}),
1533
- }, children: children }), showAxis && _jsx(TimeAxis, {})] })] }) }));
1463
+ return (_jsx(ContainerContext.Provider, { value: frame, children: _jsx(CursorContext.Provider, { value: cursorFrame, children: _jsxs("div", { style: {
1464
+ width: `${width}px`,
1465
+ // [PND-HEIGHT] A managed height makes the outer box a flex
1466
+ // column: the rows block below flexes, the axis strip keeps its
1467
+ // natural height at the bottom, and CSS subtracts one from the
1468
+ // other. That subtraction being layout rather than arithmetic is
1469
+ // the feature — the strip's height varies with label, font size,
1470
+ // calendar bands and pill lanes, so no constant is correct.
1471
+ ...(height !== undefined
1472
+ ? {
1473
+ height: `${height}px`,
1474
+ display: 'flex',
1475
+ flexDirection: 'column',
1476
+ }
1477
+ : {}),
1478
+ }, children: [_jsx("div", { style: {
1479
+ display: 'flex',
1480
+ flexDirection: 'column',
1481
+ gap: `${rowGap}px`,
1482
+ // The positioned ancestor for overlay chrome (`<Legend>`): the
1483
+ // card anchors to the rows block, never the axis strip below.
1484
+ position: 'relative',
1485
+ // The rows block takes what the axis strip leaves. `minHeight:
1486
+ // 0` lets it shrink below its content — without it a flex
1487
+ // child's floor is its content and nothing can ever get
1488
+ // smaller.
1489
+ ...(height !== undefined ? { flex: '1 1 0%', minHeight: 0 } : {}),
1490
+ }, children: children }), showAxis && _jsx(TimeAxis, {})] }) }) }));
1534
1491
  }
1535
1492
  //# sourceMappingURL=ChartContainer.js.map
@@ -1,5 +1,4 @@
1
1
  import { type ReactNode } from 'react';
2
- import { type CursorMode } from './context.js';
3
2
  export interface ChartRowProps {
4
3
  /**
5
4
  * Row height in CSS pixels — the **fixed** sizing mode. Omit it (or pass
@@ -39,16 +38,6 @@ export interface ChartRowProps {
39
38
  * hidden, so a `display: none` tab switch does not discard its scales.
40
39
  */
41
40
  flex?: number;
42
- /**
43
- * Cursor presentation for this row, overriding the container's default
44
- * ({@link ChartContainerProps.cursor}). Omit to inherit. See {@link CursorMode}.
45
- *
46
- * @deprecated Mount a cursor component **inside the row** instead
47
- * (`<ChartRow><CrosshairCursor /> …</ChartRow>`) — the per-row override with
48
- * the same nearest-mount-wins semantics. Works for one more minor; a mounted
49
- * cursor in the row overrides this prop.
50
- */
51
- cursor?: CursorMode;
52
41
  children?: ReactNode;
53
42
  }
54
43
  /**
@@ -68,5 +57,5 @@ export interface ChartRowProps {
68
57
  * Children lay out left-to-right in author order, so `<YAxis side="left"/>` goes
69
58
  * before `<Layers/>` and `<YAxis side="right"/>` after.
70
59
  */
71
- export declare function ChartRow({ height: heightProp, flex, cursor, children, }: ChartRowProps): import("react/jsx-runtime").JSX.Element;
60
+ export declare function ChartRow({ height: heightProp, flex, children, }: ChartRowProps): import("react/jsx-runtime").JSX.Element;
72
61
  //# sourceMappingURL=ChartRow.d.ts.map
package/dist/ChartRow.js CHANGED
@@ -8,7 +8,6 @@ import { resolveAxisFormat } from './format.js';
8
8
  import { resolveYTickCount } from './yticks.js';
9
9
  import { placeAxisSlots } from './slots.js';
10
10
  import { useSlotKey } from './use-slot-key.js';
11
- import { LegacyCursor } from './cursors.js';
12
11
  import { YAxis } from './YAxis.js';
13
12
  import { ContainerContext, RowContext, } from './context.js';
14
13
  /**
@@ -139,7 +138,7 @@ const TOP_LABEL_HEADER = 16;
139
138
  * Children lay out left-to-right in author order, so `<YAxis side="left"/>` goes
140
139
  * before `<Layers/>` and `<YAxis side="right"/>` after.
141
140
  */
142
- export function ChartRow({ height: heightProp, flex, cursor, children, }) {
141
+ export function ChartRow({ height: heightProp, flex, children, }) {
143
142
  const container = useContext(ContainerContext);
144
143
  if (container === null) {
145
144
  throw new Error('<ChartRow> must be rendered inside a <ChartContainer>');
@@ -212,18 +211,6 @@ export function ChartRow({ height: heightProp, flex, cursor, children, }) {
212
211
  const { registerRow } = container;
213
212
  useEffect(() => registerRow(rowKey), [registerRow, rowKey]);
214
213
  const isFirstRow = container.firstRowKey === rowKey;
215
- // Deprecation notice for the legacy `cursor` prop (dev, once per row): the
216
- // per-row override is now a cursor component mounted inside the row. The
217
- // prop keeps working via the shim rendered below.
218
- const warnedCursorRef = useRef(false);
219
- useEffect(() => {
220
- if (!isDev || cursor === undefined || warnedCursorRef.current)
221
- return;
222
- warnedCursorRef.current = true;
223
- console.warn(`[pond-charts] <ChartRow cursor="${cursor}"> is deprecated (it keeps ` +
224
- 'working this minor, removed next) — mount the cursor component ' +
225
- 'inside the row instead (docs/rfcs/interaction.md §9).');
226
- }, [cursor]);
227
214
  // Keyed by a stable per-instance id (Map preserves insertion order; setting an
228
215
  // existing key updates in place). So a re-register on a prop change keeps the
229
216
  // entry's slot — the axis-default (first axis) and layer z-order stay stable
@@ -378,7 +365,7 @@ export function ChartRow({ height: heightProp, flex, cursor, children, }) {
378
365
  const extents = needsExtents(ax)
379
366
  ? layerList
380
367
  .filter((entry) => (entry.axisId ?? defaultAxisId) === ax.id)
381
- .map((entry) => entry.layer.yExtent())
368
+ .map((entry) => entry.layer.yExtent(ax.scale))
382
369
  : [];
383
370
  const [lo, hi] = resolveYDomain(ax.min, ax.max, extents, ax.pad, ax.scale);
384
371
  // Reserve a header band at the top when any axis draws a `'top'` title,
@@ -483,7 +470,7 @@ export function ChartRow({ height: heightProp, flex, cursor, children, }) {
483
470
  // about.
484
471
  const message = logAxisWarning(ax, layerList
485
472
  .filter((entry) => (entry.axisId ?? defaultAxisId) === ax.id)
486
- .map((entry) => entry.layer.yExtent()));
473
+ .map((entry) => entry.layer.yExtent(ax.scale)));
487
474
  if (message === null)
488
475
  warned.delete(ax.id);
489
476
  else if (warned.get(ax.id) !== message) {
@@ -626,7 +613,6 @@ export function ChartRow({ height: heightProp, flex, cursor, children, }) {
626
613
  const frame = useMemo(() => ({
627
614
  height,
628
615
  topInset: topHeader,
629
- cursor,
630
616
  isFirstRow,
631
617
  rowKey,
632
618
  yScales,
@@ -649,7 +635,6 @@ export function ChartRow({ height: heightProp, flex, cursor, children, }) {
649
635
  }), [
650
636
  height,
651
637
  topHeader,
652
- cursor,
653
638
  isFirstRow,
654
639
  rowKey,
655
640
  yScales,
@@ -737,17 +722,17 @@ export function ChartRow({ height: heightProp, flex, cursor, children, }) {
737
722
  "wrap the row's <Layers>, leaving each <YAxis> a direct child of the " +
738
723
  '<ChartRow>.');
739
724
  }, [axisInsideWrapper]);
740
- return (_jsxs(RowContext.Provider, { value: frame, children: [cursor !== undefined && (_jsx(LegacyCursor, { mode: cursor, showTime: container.cursorTime, snap: container.crosshairSnap })), _jsxs("div", { ref: boxRef, style: {
741
- display: 'flex',
742
- flexDirection: 'row',
743
- width: `${container.width}px`,
744
- // Fixed rows keep their pixels; a flex row is sized by the
745
- // container's column layout and reads the result back
746
- // ([PND-HEIGHT]). `minHeight: 0` is what lets it actually shrink —
747
- // a flex child's default min-height is its content.
748
- ...(isFlex
749
- ? { flex: `${flexGrow} 1 0%`, minHeight: 0 }
750
- : { height: `${height}px` }),
751
- }, children: [leftPad > 0 && _jsx("div", { style: { flex: `0 0 ${leftPad}px` } }), leftAxisEls, plotEls, rightAxisEls, rightPad > 0 && _jsx("div", { style: { flex: `0 0 ${rightPad}px` } })] })] }));
725
+ return (_jsx(RowContext.Provider, { value: frame, children: _jsxs("div", { ref: boxRef, style: {
726
+ display: 'flex',
727
+ flexDirection: 'row',
728
+ width: `${container.width}px`,
729
+ // Fixed rows keep their pixels; a flex row is sized by the
730
+ // container's column layout and reads the result back
731
+ // ([PND-HEIGHT]). `minHeight: 0` is what lets it actually shrink —
732
+ // a flex child's default min-height is its content.
733
+ ...(isFlex
734
+ ? { flex: `${flexGrow} 1 0%`, minHeight: 0 }
735
+ : { height: `${height}px` }),
736
+ }, children: [leftPad > 0 && _jsx("div", { style: { flex: `0 0 ${leftPad}px` } }), leftAxisEls, plotEls, rightAxisEls, rightPad > 0 && _jsx("div", { style: { flex: `0 0 ${rightPad}px` } })] }) }));
752
737
  }
753
738
  //# sourceMappingURL=ChartRow.js.map
package/dist/HeatMap.d.ts CHANGED
@@ -161,9 +161,9 @@ export interface HeatMapProps<S extends SeriesSchema = SeriesSchema, VS extends
161
161
  * theme, and the M5 "theme tokens optional-with-default" gate has to land
162
162
  * first. Borrowing defers that decision instead of pre-empting it.
163
163
  *
164
- * **Pair it with `<ChartContainer cursor="none">`.** The container's default is
165
- * the shared vertical line, and on a grid that is a *second, weaker* cursor
166
- * competing with the one that already works: the cell under the pointer takes an
164
+ * **Mount no cursor component with it.** A `<LineCursor>` draws the shared
165
+ * vertical line, and on a grid that is a *second, weaker* cursor competing
166
+ * with the one that already works: the cell under the pointer takes an
167
167
  * outline, which says both axes at once. The line says only x, and a heat map's
168
168
  * x position is rarely the question. The pointer's own crosshair shape plus the
169
169
  * cell outline is the whole affordance.
package/dist/HeatMap.js CHANGED
@@ -61,9 +61,9 @@ function marksOf(set) {
61
61
  * theme, and the M5 "theme tokens optional-with-default" gate has to land
62
62
  * first. Borrowing defers that decision instead of pre-empting it.
63
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
64
+ * **Mount no cursor component with it.** A `<LineCursor>` draws the shared
65
+ * vertical line, and on a grid that is a *second, weaker* cursor competing
66
+ * with the one that already works: the cell under the pointer takes an
67
67
  * outline, which says both axes at once. The line says only x, and a heat map's
68
68
  * x position is rarely the question. The pointer's own crosshair shape plus the
69
69
  * cell outline is the whole affordance.