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
7 changes: 7 additions & 0 deletions .changeset/calm-arcs-render.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@tanstack/charts': patch
'@tanstack/angular-charts': patch
---

Keep animated SVG arc flags valid throughout path interpolation and prevent the
Angular adapter from mounting its browser host during server rendering.
56 changes: 56 additions & 0 deletions API-FRICTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ Each entry records:
| F-265 | Sunburst motion lost hierarchy across enter and exit | API | resolved |
| F-266 | Path-token motion distorted polar sectors | API/Tooling | resolved |
| F-267 | Stress timeouts entered a class temporal dead zone | Tooling | resolved |
| F-268 | Animated arc flags became invalid fractional path values | API | resolved |
| F-269 | Angular mounted its browser host during server rendering | API | resolved |
| F-270 | Catalog migration left generated release evidence stale | Tooling | resolved |

## Findings

Expand Down Expand Up @@ -7898,3 +7901,56 @@ Each entry records:
with the expected prototype, name, and duration message. The retry suite,
stress-runner syntax check, full repository validation, and rerun GitHub
stress partition pass.

### F-268 — Animated arc flags became invalid fractional path values

- Status: resolved
- Severity: high
- Owner: API
- Observed in: GitHub issue #71 and the SVG reconciliation regression
- Friction: the default motion renderer interpolated every number in a path's
`d` attribute. SVG arc flags are discrete `0` or `1` values, so a flag change
produced invalid fractional flags and could hide an arc during its tween.
- Decision: identify the large-arc and sweep positions in every `A`/`a`
command, snap those values to the target flag, and continue interpolating the
remaining path geometry.
- Verification: the focused reconciliation test changes both flags while
interpolating arc radii and endpoints, and asserts valid flags at the
midpoint and exact target geometry at completion. A second regression covers
the SVG grammar's adjacent `00` and `01` flag pairs. Bundle review attributes
250 minified and 133–145 gzip bytes across the four locked DOM consumers to the
shared correctness fix; the exact baselines and six complete-consumer
ceilings record that reviewed cost.

### F-269 — Angular mounted its browser host during server rendering

- Status: resolved
- Severity: high
- Owner: API
- Observed in: GitHub issue #56 and Angular server-rendering regression
- Friction: `ngAfterViewInit` runs during Angular SSR, so the adapter mounted
the DOM host against the server element and called browser-only measurement
or mutation methods.
- Decision: keep synchronous SVG prerendering in the shared adapter and defer
only browser-host mounting through Angular's `afterNextRender`, which does
not run on the server.
- Verification: the official Angular `renderApplication` pipeline emits the
complete labeled SVG without mounting the DOM host, while the existing
browser test still covers mount, update, and destroy.

### F-270 — Catalog migration left generated release evidence stale

- Status: resolved
- Severity: high
- Owner: Tooling
- Observed in: release validation after the React catalog migration in #84
- Friction: the migration moved four application shells into React views and
renamed the token-calendar shell to TSX without updating roadmap ownership
or the audit link. It also changed catalog source inputs without refreshing
preview provenance. Current `main` therefore failed both the unit and
catalog-preview release gates.
- Decision: point roadmap ownership at the active `view.tsx` and `shell.tsx`
files, repair the audit link, and regenerate catalog preview provenance.
- Verification: the focused roadmap test and catalog preview check pass. The
only rendered asset change normalizes synchronized-cursor point keys from
timestamp labels to the migrated ISO date labels; geometry is unchanged.
6 changes: 3 additions & 3 deletions benchmarks/bundle-size/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ may add only its transport module over the tooltip consumer. Ordinary line,
compact-scale, and tooltip kernels also reject all transform modules.

The compact linear scene and React consumer are both locked and budgeted. The
scene has a 10.3 KiB gzip ceiling. The React compact-scale line consumer has a
26.6 KiB ceiling with React and React DOM external. `d3-array` tick helpers are
scene has a 10.55 KiB gzip ceiling. The React compact-scale line consumer has a
27.05 KiB ceiling with React and React DOM external. `d3-array` tick helpers are
allowed only in the compact linear path; categorical compact-scale kernels
reject every D3 runtime input. All compact fixtures reject `d3-scale`,
`d3-format`, `d3-interpolate`, `d3-color`, and `internmap`.
Expand All @@ -42,7 +42,7 @@ of the default scene and host contracts. Default static SVG consumes scene
clips and gradients. Their reviewed shared-path cost is recorded in the locked
entries and the corresponding complete-consumer budgets. Rolling path planning
remains confined to the opt-in motion renderer, whose complete SVG budget is
17.2 KiB gzip.
18.2 KiB gzip.

Every public transform family has an isolated budget and retained-input
allowlist. Numeric and 2D bins may retain `d3-array`, and row stacks may retain
Expand Down
16 changes: 8 additions & 8 deletions benchmarks/bundle-size/universal-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@
"gzip": 26201
},
"TanStack DOM host": {
"bytes": 70320,
"gzip": 24623
"bytes": 70570,
"gzip": 24758
},
"React adapter": {
"bytes": 72479,
"gzip": 25379
"bytes": 72729,
"gzip": 25524
},
"React line consumer": {
"bytes": 95673,
"gzip": 34616
"bytes": 95923,
"gzip": 34754
},
"Compact-scale line scene": {
"bytes": 29572,
"gzip": 10769
},
"React compact-scale line consumer": {
"bytes": 78174,
"gzip": 27551
"bytes": 78424,
"gzip": 27684
},
"Custom-scale line scene": {
"bytes": 27756,
Expand Down
128 changes: 64 additions & 64 deletions benchmarks/comparison/bundle-baseline.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"schemaVersion": 4,
"generatedAt": "2026-08-11T00:43:02.982Z",
"generatedAt": "2026-08-11T23:49:36.793Z",
"packageVersions": {
"tanstack": "0.10.0",
"tanstack": "0.11.0",
"chartjs": "4.5.1",
"echarts": "6.1.0",
"recharts": "3.10.1",
Expand All @@ -11,8 +11,8 @@
"sources": {
"tanstack": {
"kind": "workspace",
"revision": "7ac3c321ff253f51d2c7df7be6a63c6edb7b771f",
"inputDigest": "sha256:44f03725e05260cba794012df73385ad7df1ccd9a7cd44ad2e560a05ebf682e7"
"revision": "02e24867f1699fa918fd49eaedfad64bc3f4e9e5",
"inputDigest": "sha256:790fc8c0e954afbba943d637d43b665739d2438d2cc6c341e81613baad327508"
},
"chartjs": {
"kind": "package",
Expand Down Expand Up @@ -45,88 +45,88 @@
},
"bundles": {
"tanstack-line-basic": {
"minifiedBytes": 105194,
"gzipBytes": 38218,
"brotliBytes": 33855,
"incrementalGzipBytes": 38218,
"incrementalBrotliBytes": 33855
"minifiedBytes": 105444,
"gzipBytes": 38355,
"brotliBytes": 33936,
"incrementalGzipBytes": 38355,
"incrementalBrotliBytes": 33936
},
"tanstack-line-interactive": {
"minifiedBytes": 110635,
"gzipBytes": 40001,
"brotliBytes": 35257,
"incrementalGzipBytes": 40001,
"incrementalBrotliBytes": 35257
"minifiedBytes": 110885,
"gzipBytes": 40139,
"brotliBytes": 35457,
"incrementalGzipBytes": 40139,
"incrementalBrotliBytes": 35457
},
"tanstack-line-advanced": {
"minifiedBytes": 117823,
"gzipBytes": 42310,
"brotliBytes": 37208,
"incrementalGzipBytes": 42310,
"incrementalBrotliBytes": 37208
"minifiedBytes": 118073,
"gzipBytes": 42438,
"brotliBytes": 37478,
"incrementalGzipBytes": 42438,
"incrementalBrotliBytes": 37478
},
"tanstack-bar-basic": {
"minifiedBytes": 113723,
"gzipBytes": 41389,
"brotliBytes": 36502,
"incrementalGzipBytes": 41389,
"incrementalBrotliBytes": 36502
"minifiedBytes": 113973,
"gzipBytes": 41522,
"brotliBytes": 36650,
"incrementalGzipBytes": 41522,
"incrementalBrotliBytes": 36650
},
"tanstack-bar-interactive": {
"minifiedBytes": 118015,
"gzipBytes": 42734,
"brotliBytes": 37678,
"incrementalGzipBytes": 42734,
"incrementalBrotliBytes": 37678
"minifiedBytes": 118265,
"gzipBytes": 42870,
"brotliBytes": 37747,
"incrementalGzipBytes": 42870,
"incrementalBrotliBytes": 37747
},
"tanstack-bar-advanced": {
"minifiedBytes": 118354,
"gzipBytes": 42878,
"brotliBytes": 37752,
"incrementalGzipBytes": 42878,
"incrementalBrotliBytes": 37752
"minifiedBytes": 118604,
"gzipBytes": 43012,
"brotliBytes": 37919,
"incrementalGzipBytes": 43012,
"incrementalBrotliBytes": 37919
},
"tanstack-area-basic": {
"minifiedBytes": 110281,
"gzipBytes": 40134,
"brotliBytes": 35524,
"incrementalGzipBytes": 40134,
"incrementalBrotliBytes": 35524
"minifiedBytes": 110531,
"gzipBytes": 40265,
"brotliBytes": 35653,
"incrementalGzipBytes": 40265,
"incrementalBrotliBytes": 35653
},
"tanstack-area-interactive": {
"minifiedBytes": 115722,
"gzipBytes": 41869,
"brotliBytes": 36921,
"incrementalGzipBytes": 41869,
"incrementalBrotliBytes": 36921
"minifiedBytes": 115972,
"gzipBytes": 42001,
"brotliBytes": 37115,
"incrementalGzipBytes": 42001,
"incrementalBrotliBytes": 37115
},
"tanstack-area-advanced": {
"minifiedBytes": 123092,
"gzipBytes": 44314,
"brotliBytes": 38976,
"incrementalGzipBytes": 44314,
"incrementalBrotliBytes": 38976
"minifiedBytes": 123342,
"gzipBytes": 44453,
"brotliBytes": 39193,
"incrementalGzipBytes": 44453,
"incrementalBrotliBytes": 39193
},
"tanstack-scatter-basic": {
"minifiedBytes": 106233,
"gzipBytes": 38602,
"brotliBytes": 34108,
"incrementalGzipBytes": 38602,
"incrementalBrotliBytes": 34108
"minifiedBytes": 106483,
"gzipBytes": 38737,
"brotliBytes": 34248,
"incrementalGzipBytes": 38737,
"incrementalBrotliBytes": 34248
},
"tanstack-scatter-interactive": {
"minifiedBytes": 111674,
"gzipBytes": 40354,
"brotliBytes": 35550,
"incrementalGzipBytes": 40354,
"incrementalBrotliBytes": 35550
"minifiedBytes": 111924,
"gzipBytes": 40487,
"brotliBytes": 35678,
"incrementalGzipBytes": 40487,
"incrementalBrotliBytes": 35678
},
"tanstack-scatter-advanced": {
"minifiedBytes": 111690,
"gzipBytes": 40358,
"brotliBytes": 35533,
"incrementalGzipBytes": 40358,
"incrementalBrotliBytes": 35533
"minifiedBytes": 111940,
"gzipBytes": 40494,
"brotliBytes": 35700,
"incrementalGzipBytes": 40494,
"incrementalBrotliBytes": 35700
},
"chartjs-line-basic": {
"minifiedBytes": 137909,
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/conformance/DEFINITION-COVERAGE-AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ ownership boundary.
| [114 — Spring line](./cases/114-spring-line-motion/tanstack.ts) | Definition now | Line morph and per-series spring overrides are already declarative; demo controls remain outside. |
| [115 — Definition motion](./cases/115-definition-motion/tanstack.ts) | Definition now | Chart, mark, datum, axis, tick, and label motion are already definition-owned. |
| [117 — Focus cursor motion](./cases/117-focus-cursor-motion/tanstack.ts) | First-party primitive | Add a stable-key focus guide with x/y rules, marker, labels, and normal motion; remove the second SVG and spring loop. |
| [118 — Token calendar](./cases/118-token-usage-calendar/shell.ts) | First-party primitive | Add per-tick text style, anchor, and offset accessors so the first month label needs no post-render DOM mutation. |
| [118 — Token calendar](./cases/118-token-usage-calendar/shell.tsx) | First-party primitive | Add per-tick text style, anchor, and offset accessors so the first month label needs no post-render DOM mutation. |
| [119 — Stacked bar cursor](./cases/119-stacked-bar-band-cursor/chart.ts) | First-party primitive | Use renderer-native `crosshair` axes for the categorical band, endpoint rule, labels, grouped focus, and ordinary definition motion; only conformance observation remains outside. |
| [120 — Themed area card](./cases/120-themed-interactive-area/chart.ts) | Definition now | Native area, line, points, gradients, sparse guides, tooltip, and keyed spring policy own the chart; the range selector and card remain application UI. |
| [121 — Active bar dashboard](./cases/121-active-bar-dashboard/chart.ts) | Definition now | Native gradient bars, focus states, band cursor, tooltip, and spring updates own the chart; KPI totals double as application-owned series controls. |
Expand Down
14 changes: 7 additions & 7 deletions benchmarks/conformance/definition-coverage-roadmap.json
Original file line number Diff line number Diff line change
Expand Up @@ -2443,7 +2443,7 @@
"evidence": [
"cases/85-scrollable-resource-lanes/tanstack.ts",
"cases/85-scrollable-resource-lanes/tanstack.test.ts",
"cases/85-scrollable-resource-lanes/shell.ts",
"cases/85-scrollable-resource-lanes/view.tsx",
"DEFINITION-COVERAGE-PLAN.md"
],
"work": [
Expand All @@ -2452,15 +2452,15 @@
"stage": "post-render",
"owner": "application",
"coordinateSpace": "dom",
"sources": ["shell.ts"],
"sources": ["view.tsx"],
"summary": "Retain native overflow, content-width and scroll-preservation policy, the fixed rail and legend, persistent task summary, and complete schedule alternative."
},
{
"kind": "interaction-controller",
"stage": "post-render",
"owner": "application",
"coordinateSpace": "dom",
"sources": ["tanstack.ts", "shell.ts"],
"sources": ["tanstack.ts", "view.tsx"],
"summary": "Use the chart-owned focused point to reveal an offscreen task in the parent scroll viewport and update the persistent summary."
}
]
Expand Down Expand Up @@ -2529,7 +2529,7 @@
"stage": "post-render",
"owner": "application",
"coordinateSpace": "dom",
"sources": ["summary.ts"],
"sources": ["view.tsx"],
"summary": "Retain the cross-view live value summary as an observer of chart-owned focus and selection events."
}
]
Expand Down Expand Up @@ -2566,7 +2566,7 @@
"stage": "post-render",
"owner": "application",
"coordinateSpace": "dom",
"sources": ["controls.ts"],
"sources": ["view.tsx"],
"summary": "Retain domain-specific semantic sliders and live status text over the same controlled position."
}
]
Expand Down Expand Up @@ -2700,7 +2700,7 @@
"stage": "before-definition",
"owner": "application",
"coordinateSpace": "none",
"sources": ["tanstack.ts", "controls.ts", "model.ts"],
"sources": ["tanstack.ts", "view.tsx", "model.ts"],
"summary": "Retain the date input, validation, event constraint, accepted end, commit transaction, status, and exact-value alternative."
}
],
Expand Down Expand Up @@ -3415,7 +3415,7 @@
"stage": "before-definition",
"owner": "application",
"coordinateSpace": "dom",
"sources": ["layout.ts", "shell.ts"],
"sources": ["layout.ts", "shell.tsx"],
"summary": "Retain width-derived host sizing and tooltip presentation."
}
]
Expand Down
5 changes: 4 additions & 1 deletion benchmarks/conformance/definition-coverage-roadmap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,10 @@ describe('definition coverage roadmap', () => {
if (source.includes('/')) {
expect(source).toMatch(/^(?:benchmarks|docs|packages|scripts)\//u)
} else {
expect(authoredClosure.has(source)).toBe(true)
expect(
authoredClosure.has(source),
`${entry.id}: ${source} is not reachable from tanstack.ts`,
).toBe(true)
}
expect(existsSync(sourcePath)).toBe(true)
}
Expand Down
Loading