@pond-ts/react 0.62.0 → 0.63.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 (2) hide show
  1. package/CHANGELOG.md +101 -1
  2. package/package.json +2 -2
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.62.0...HEAD
11
+ [Unreleased]: https://github.com/pond-ts/pond/compare/v0.63.0...HEAD
12
+ [0.63.0]: https://github.com/pond-ts/pond/compare/v0.62.0...v0.63.0
12
13
  [0.62.0]: https://github.com/pond-ts/pond/compare/v0.61.0...v0.62.0
13
14
  [0.61.0]: https://github.com/pond-ts/pond/compare/v0.60.0...v0.61.0
14
15
  [0.60.0]: https://github.com/pond-ts/pond/compare/v0.59.0...v0.60.0
@@ -65,6 +66,105 @@ include new features and type-level changes; patch bumps are strictly additive.
65
66
 
66
67
  ## [Unreleased]
67
68
 
69
+ ## [0.63.0] — 2026-08-18
70
+
71
+ ### Added
72
+
73
+ - `@pond-ts/charts`: **axis pan/zoom**, behind a new
74
+ **`<ChartContainer axisPanZoom>`** (`'none'` — the default — / `'x'` / `'y'` /
75
+ `'xy'`). Opted in, the `<XAxis>` strip and each `<YAxis>` gutter become
76
+ grabbable, and **double-click** puts one back (the declared `range` on x, its
77
+ fit on y). The cursor stays an ordinary arrow at rest and becomes directional
78
+ (`↕` / `↔`) only while a gesture is running.
79
+
80
+ **The opt-in is deliberately separate from `panZoom`, in both directions.** An
81
+ already-interactive chart does not grow axis gestures on upgrade — nothing
82
+ changes for any existing chart — and a chart can scale its y axes with
83
+ `panZoom` off entirely, which is what you want when the plot's drag belongs to
84
+ a selection sweep.
85
+
86
+ **The x strip is the canvas gesture, moved to the axis** — drag pans, wheel
87
+ zooms about the pointer — reusing the plot's own domain-space maths, so
88
+ `bounds` and `minDuration` still fence the view and a trading-time axis still
89
+ pans and floors in _trading_ time. A category axis has no continuous domain and
90
+ stays inert.
91
+
92
+ **A y gutter zooms, and only the axis you grabbed** — its sibling and every
93
+ other row hold still. That needed a new per-axis pixel transform
94
+ (`RowFrame.axisTransforms`, layered under the container's uniform
95
+ `yTransform`), since the uniform one exists precisely so a _plot_ gesture never
96
+ has to pick an axis; unlike it, this is not floored at `k ≥ 1`, because
97
+ squashing an axis you grabbed is the point.
98
+
99
+ - `@pond-ts/charts`: **`<YAxis onBoundsChange>`** — the auto-vs-manual hand-off
100
+ for a scaled y axis. Fires with the `[min, max]` a gutter gesture reached, and
101
+ with `null` when the axis is released back to auto-fit, so a UI can show the
102
+ bounds, badge the scale "manual", and offer a toggle back. Providing it makes
103
+ the axis **controlled** (the gesture only reports; `min`/`max` fed back are
104
+ what it draws), exactly as `onTimeRangeChange` does for the x view; omit it and
105
+ the axis holds the zoom itself. `ContainerFrame` also gains `seedRange` — the
106
+ declared view, as against the gestured `timeRange` — which is the x reset's
107
+ target.
108
+
109
+ - **charts: `<ChartContainer height>` + `<ChartRow flex>` — container-owned
110
+ vertical layout** ([PND-HEIGHT]). `height` takes a pixel number or `'auto'`
111
+ (measured by the same `ResizeObserver` as `width="auto"`); omitted stays the
112
+ classic mode where rows declare pixels. A managed container renders as a
113
+ **flex column** — the rows block flexes, the x-axis strip keeps its natural
114
+ height — and flex rows (a bare `<ChartRow>` is `flex={1}`) divide what the
115
+ browser says is left, then read that height back for their y-scales.
116
+
117
+ The design constraint was that **CSS does the subtraction**: the axis
118
+ strip's height depends on its `label`, the theme font size, the tick
119
+ ladder's calendar band row at the current grain, and stacked marker pills —
120
+ it is not a constant a caller can subtract, and every consumer who tried
121
+ carried a wrong one (`20` and `24` in one codebase; this site's own
122
+ resizable-panels recipe said `22`). It also means non-row children between
123
+ rows — the recipe's draggable splitter — keep taking their natural space,
124
+ so that recipe reduces to its drag handler: one flex row absorbing slack
125
+ over one fixed row the drag resizes, no `AXIS_H`, no measuring hook.
126
+
127
+ A flex row paints nothing until its first measurement, latches its last
128
+ non-zero height while hidden (a `display: none` tab switch keeps its
129
+ scales), and warns in dev when mounted in a container that never sizes it.
130
+ The container **warns in dev when a measured dimension stays 0** — the
131
+ unconstrained-parent deadlock, which for height is the _default_ (a
132
+ flex-column child's height is its content) rather than an edge case.
133
+
134
+ Fixed-`height` rows keep their pixels everywhere, managed or not; a
135
+ container with no `height` behaves exactly as before.
136
+
137
+ ### Fixed
138
+
139
+ - **charts: the crosshair's value pill lands on the axis that measured the
140
+ value, in that axis's colour.** With two y-axes on one side, the pill was
141
+ placed by side alone — always against the plot edge — so a reading taken off
142
+ the **outer** axis appeared over the **inner** axis's ticks, in the cursor's
143
+ grey: a number pinned to a ruler that never measured it. The reticle picks one
144
+ series, so the resolved sample now carries its axis's gutter **offset** (the
145
+ reserved widths of the columns between it and the plot) and its
146
+ `<YAxis color>`, and the pill uses both — position _and_ ink say which of two
147
+ stacked scales the number is on. A single axis per side is unchanged (offset
148
+ `0`), as is an axis that sets no colour (the theme's cursor ink).
149
+
150
+ A pill placed further out is now **bridged back to the plot edge** by a 1px
151
+ connector in its own colour — the y-side twin of the crosshair's x-axis time
152
+ connector, without which a pill a column out reads as a value floating in a
153
+ gutter. It draws at half opacity because, unlike the time connector's empty
154
+ strip, it crosses another axis's tick labels; nothing is drawn on the innermost
155
+ axis, where the pill already meets the line.
156
+
157
+ `<YAxis color>` is now part of the axis's registered spec rather than
158
+ presentation-only, because the pill is drawn by the row's cursor overlay, not
159
+ by `<YAxis>`. `<Baseline indicator>` — the other on-axis value pill — got the
160
+ same placement fix and the same connector. New `Cursors/Crosshair` stories fan
161
+ the states out (`AxisColor`, `StackedAxes`, `StackedAxesColored`,
162
+ `StackedAxesLeft`, `StackedAxesBothSides`).
163
+
164
+ Not covered: `<YAxisIndicator>` still takes an explicit `side` alongside its
165
+ `axis`, so it can be pointed at a gutter its axis isn't in; reconciling those
166
+ two props is a public-API question, left for its own change.
167
+
68
168
  ## [0.62.0] — 2026-08-16
69
169
 
70
170
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/react",
3
- "version": "0.62.0",
3
+ "version": "0.63.0",
4
4
  "description": "React hooks for pond-ts live time series",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "test:runtime": "vitest run"
35
35
  },
36
36
  "peerDependencies": {
37
- "pond-ts": "^0.62.0",
37
+ "pond-ts": "^0.63.0",
38
38
  "react": "^18.0.0 || ^19.0.0"
39
39
  },
40
40
  "devDependencies": {