Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lightweight-svg-motion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/charts': minor
---

Add the opt-in `motionLite()` renderer from `@tanstack/charts/motion/lite` for whole-chart fade entrances and keyed SVG transitions without the full motion engine. Existing `motion()` behavior is unchanged.
13 changes: 13 additions & 0 deletions API-FRICTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -5865,6 +5865,19 @@ Each entry records:
integration test mounts a definition containing both legacy `animate` and a
conflicting definition-level motion duration, then verifies that the
host-level motion renderer owns the transition timing.
- Follow-up from #205: an entrance/basic-update consumer retained the complete
motion engine. After measuring a private prototype, the owner approved a
separate opt-in `motionLite()` entry, not a change to `motion()`. It reuses
the existing SVG reconciler, owns only duration/easing/entrance/resize policy,
and documents destination-based interaction during updates. Definition-local
timing and tooltip spring inheritance remain exclusive to full motion.
- Follow-up verification: focused tests cover static prerender parity,
hydration without replay, keyed interruption, resize policy, reduced motion,
zero duration, invalid durations, and cleanup. Packed imports and declarations
pass, excluding full motion, springs, tooltip implementation, and D3. Three
browsers pass interrupted exits, hydration, reduced motion, line/pie endpoints,
and authored opacity. All 114 existing consumer outputs are byte-identical to
main. Full validation remains the publication gate.

### F-190 — Static conformance sampled active motion

Expand Down
4 changes: 2 additions & 2 deletions benchmarks/comparison/bundle-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"sources": {
"tanstack": {
"kind": "workspace",
"revision": "28a0626e3859d2e0ebd33772bf81ebc2c402b09a",
"inputDigest": "sha256:b0e66aa78ec68bebdd7a9305693d559fd68f0946b82cb1909a851c3704895eb6"
"revision": "69d70960dd6b29f3706a173d348f2fc8271b0dcc",
"inputDigest": "sha256:80f5c5447f39757715be5def33eed28b12869946936369671243436701fb7964"
},
"chartjs": {
"kind": "package",
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/conformance/previews/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schemaVersion": 1,
"width": 288,
"height": 192,
"sourceHash": "54ad8bcd52292af01eb73439aebd5ca4186c06ece050bb2d0118406cc36c88ec",
"sourceHash": "408fe8d6fb17b71b48ce505eb93dfe8d34afaf2b99dcd855c8b789d78e7cd486",
"assets": [
{
"id": "01-line-gaps",
Expand Down
4 changes: 2 additions & 2 deletions docs/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ turning untested behavior into a checkmark.

| Library | Package | Measured source |
| -------------------------------------------------------------------------------------- | -------------------- | ------------------- |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `28a0626` |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `69d7096` |
| [Chart.js](https://www.chartjs.org/docs/latest/) | `chart.js` | npm `4.5.1` |
| [Apache ECharts](https://echarts.apache.org/handbook/en/best-practices/canvas-vs-svg/) | `echarts` | npm `6.1.0` |
| [Recharts](https://recharts.github.io/en-US/) | `recharts` | npm `3.10.1` |
| [Observable Plot](https://observablehq.com/plot/features/plots) | `@observablehq/plot` | npm `0.6.17` |

The competitor versions are exact package pins, not latest versions inferred
at page render time. The measured TanStack workspace revision is `28a0626`.
at page render time. The measured TanStack workspace revision is `69d7096`.

## Capability matrix

Expand Down
1 change: 1 addition & 0 deletions docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ aggregate `/scales` export.
| `@tanstack/charts/mark/scale-values` | `createMarkWithScaleValues` |
| `@tanstack/charts/motion` | `motion`, `stagger`, `ChartMotionOptions`, and renderer-neutral motion types |
| `@tanstack/charts/motion/definition` | Isolated `stagger` and `ChartMotionStaggerOptions` without the renderer or spring solver |
| `@tanstack/charts/motion/lite` | `motionLite` and `ChartMotionLiteOptions` for whole-chart fade entrance and basic keyed SVG updates |
| `@tanstack/charts/network/force` | `forceLayout`, built-in descriptors, named D3-compatible force factories, private working-clone context, settled node/link result, and lineage types |
| `@tanstack/charts/network/sankey` | `sankeyDiagram`, shorthand and callable alignment types, responsive layout options, immutable node/link values, comparator contexts, and lineage types |
| `@tanstack/charts/polar` | `pie`, `polar`, `focusGroupAngle`, `radialArc`, `radialBarRadius`, `radialBarAngle`, other radial marks, and radial/angle guides |
Expand Down
48 changes: 48 additions & 0 deletions docs/reference/motion.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and Canvas do not import a clock or physics solver.

## `motion`

For a smaller renderer with whole-chart fade entrance and basic keyed SVG
updates, use [`motionLite`](#motionlite). Keep `motion()` for springs,
definition-local timing, rolling paths, and animated interaction geometry.

```ts
import { motion } from '@tanstack/charts/motion'

Expand Down Expand Up @@ -474,3 +478,47 @@ option do not currently provide an equivalent supported class hook.
- Static SVG and Canvas ignore definition motion and paint final geometry.
- The optional renderer is browser SVG only; it is not a Web Animations, View
Transitions, Canvas, or native adapter.

## `motionLite`

```ts
import { motionLite } from '@tanstack/charts/motion/lite'

const renderer = motionLite({ duration: 240, easing: 'ease-out' })
```

Pass this renderer to the DOM host or a browser framework adapter. Import it
directly from `/motion/lite`; it is not re-exported from the root or `/motion`.
Existing `motion()` imports and behavior are unchanged.

### `ChartMotionLiteOptions`

The optional argument to `motionLite()` has the following fields.

`motionLite()` fades the entire SVG, including guides, on the first client
paint. Updates reuse keyed SVG nodes and tween compatible numeric attributes
and path command skeletons. New and removed keyed elements fade; incompatible
path skeletons snap to the new path. Adopted server-rendered SVG does not replay
the entrance. Static prerendering always paints final geometry.

| Option | Default | Meaning |
| ---------------------- | ------------ | -------------------------------------------------------------- |
| `initial` | `true` | Fade the first client paint |
| `duration` | `240` | Finite, non-negative milliseconds; `0` disables animation |
| `easing` | `'ease-out'` | `linear`, `ease`, `ease-in`, `ease-out`, or `ease-in-out` |
| `respectReducedMotion` | `true` | Snap renders when the user's reduced-motion preference matches |
| `resize` | `false` | Tween size changes instead of committing immediately |

The entrance uses browser CSS easing through Web Animations. Updates use the
SVG reconciler's named easing curves. If Web Animations is unavailable, the
first paint is immediate and supported SVG updates still animate. Updates
during entrance keep the fade running; a reduced-motion render or an immediate
resize cancels it. Destroying the host cancels both entrance and update motion.

This renderer owns its duration and easing, ignoring `svgAnimation` and
definition-level motion timing. It does not include springs, velocity
continuity, staggering, rolling paths, specialized bar/arc entrances, or
inherited tooltip motion. Default focus and inline states use the existing SVG
renderer. Hit testing and tooltips use destination geometry during updates,
not interpolated presentation points. Use `motion()` when interactions must
follow moving marks, or for definition-local timing and tooltip springs.
4 changes: 2 additions & 2 deletions packages/charts-core/docs/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ turning untested behavior into a checkmark.

| Library | Package | Measured source |
| -------------------------------------------------------------------------------------- | -------------------- | ------------------- |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `28a0626` |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `69d7096` |
| [Chart.js](https://www.chartjs.org/docs/latest/) | `chart.js` | npm `4.5.1` |
| [Apache ECharts](https://echarts.apache.org/handbook/en/best-practices/canvas-vs-svg/) | `echarts` | npm `6.1.0` |
| [Recharts](https://recharts.github.io/en-US/) | `recharts` | npm `3.10.1` |
| [Observable Plot](https://observablehq.com/plot/features/plots) | `@observablehq/plot` | npm `0.6.17` |

The competitor versions are exact package pins, not latest versions inferred
at page render time. The measured TanStack workspace revision is `28a0626`.
at page render time. The measured TanStack workspace revision is `69d7096`.

## Capability matrix

Expand Down
1 change: 1 addition & 0 deletions packages/charts-core/docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ aggregate `/scales` export.
| `@tanstack/charts/mark/scale-values` | `createMarkWithScaleValues` |
| `@tanstack/charts/motion` | `motion`, `stagger`, `ChartMotionOptions`, and renderer-neutral motion types |
| `@tanstack/charts/motion/definition` | Isolated `stagger` and `ChartMotionStaggerOptions` without the renderer or spring solver |
| `@tanstack/charts/motion/lite` | `motionLite` and `ChartMotionLiteOptions` for whole-chart fade entrance and basic keyed SVG updates |
| `@tanstack/charts/network/force` | `forceLayout`, built-in descriptors, named D3-compatible force factories, private working-clone context, settled node/link result, and lineage types |
| `@tanstack/charts/network/sankey` | `sankeyDiagram`, shorthand and callable alignment types, responsive layout options, immutable node/link values, comparator contexts, and lineage types |
| `@tanstack/charts/polar` | `pie`, `polar`, `focusGroupAngle`, `radialArc`, `radialBarRadius`, `radialBarAngle`, other radial marks, and radial/angle guides |
Expand Down
48 changes: 48 additions & 0 deletions packages/charts-core/docs/reference/motion.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and Canvas do not import a clock or physics solver.

## `motion`

For a smaller renderer with whole-chart fade entrance and basic keyed SVG
updates, use [`motionLite`](#motionlite). Keep `motion()` for springs,
definition-local timing, rolling paths, and animated interaction geometry.

```ts
import { motion } from '@tanstack/charts/motion'

Expand Down Expand Up @@ -474,3 +478,47 @@ option do not currently provide an equivalent supported class hook.
- Static SVG and Canvas ignore definition motion and paint final geometry.
- The optional renderer is browser SVG only; it is not a Web Animations, View
Transitions, Canvas, or native adapter.

## `motionLite`

```ts
import { motionLite } from '@tanstack/charts/motion/lite'

const renderer = motionLite({ duration: 240, easing: 'ease-out' })
```

Pass this renderer to the DOM host or a browser framework adapter. Import it
directly from `/motion/lite`; it is not re-exported from the root or `/motion`.
Existing `motion()` imports and behavior are unchanged.

### `ChartMotionLiteOptions`

The optional argument to `motionLite()` has the following fields.

`motionLite()` fades the entire SVG, including guides, on the first client
paint. Updates reuse keyed SVG nodes and tween compatible numeric attributes
and path command skeletons. New and removed keyed elements fade; incompatible
path skeletons snap to the new path. Adopted server-rendered SVG does not replay
the entrance. Static prerendering always paints final geometry.

| Option | Default | Meaning |
| ---------------------- | ------------ | -------------------------------------------------------------- |
| `initial` | `true` | Fade the first client paint |
| `duration` | `240` | Finite, non-negative milliseconds; `0` disables animation |
| `easing` | `'ease-out'` | `linear`, `ease`, `ease-in`, `ease-out`, or `ease-in-out` |
| `respectReducedMotion` | `true` | Snap renders when the user's reduced-motion preference matches |
| `resize` | `false` | Tween size changes instead of committing immediately |

The entrance uses browser CSS easing through Web Animations. Updates use the
SVG reconciler's named easing curves. If Web Animations is unavailable, the
first paint is immediate and supported SVG updates still animate. Updates
during entrance keep the fade running; a reduced-motion render or an immediate
resize cancels it. Destroying the host cancels both entrance and update motion.

This renderer owns its duration and easing, ignoring `svgAnimation` and
definition-level motion timing. It does not include springs, velocity
continuity, staggering, rolling paths, specialized bar/arc entrances, or
inherited tooltip motion. Default focus and inline states use the existing SVG
renderer. Hit testing and tooltips use destination geometry during updates,
not interpolated presentation points. Use `motion()` when interactions must
follow moving marks, or for definition-local timing and tooltip springs.
5 changes: 5 additions & 0 deletions packages/charts-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
"./lit": "./src/lit.ts",
"./motion": "./src/motion.ts",
"./motion/definition": "./src/motion-definition.ts",
"./motion/lite": "./src/motion-lite.ts",
"./network/force": "./src/network-force.ts",
"./network/sankey": "./src/network-sankey.ts",
"./octane": "./src/octane.ts",
Expand Down Expand Up @@ -411,6 +412,10 @@
"types": "./dist/motion-definition.d.ts",
"import": "./dist/motion-definition.js"
},
"./motion/lite": {
"types": "./dist/motion-lite.d.ts",
"import": "./dist/motion-lite.js"
},
"./network/force": {
"types": "./dist/network-force.d.ts",
"import": "./dist/network-force.js"
Expand Down
Loading