diff --git a/.changeset/calm-arcs-render.md b/.changeset/calm-arcs-render.md
new file mode 100644
index 00000000..56026e9b
--- /dev/null
+++ b/.changeset/calm-arcs-render.md
@@ -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.
diff --git a/API-FRICTION.md b/API-FRICTION.md
index ca926dba..a424e447 100644
--- a/API-FRICTION.md
+++ b/API-FRICTION.md
@@ -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
@@ -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.
diff --git a/benchmarks/bundle-size/README.md b/benchmarks/bundle-size/README.md
index 9c182276..74df5685 100644
--- a/benchmarks/bundle-size/README.md
+++ b/benchmarks/bundle-size/README.md
@@ -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`.
@@ -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
diff --git a/benchmarks/bundle-size/universal-baseline.json b/benchmarks/bundle-size/universal-baseline.json
index b6dee166..fd9f6438 100644
--- a/benchmarks/bundle-size/universal-baseline.json
+++ b/benchmarks/bundle-size/universal-baseline.json
@@ -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,
diff --git a/benchmarks/comparison/bundle-baseline.json b/benchmarks/comparison/bundle-baseline.json
index 6910d01c..fed1b2cf 100644
--- a/benchmarks/comparison/bundle-baseline.json
+++ b/benchmarks/comparison/bundle-baseline.json
@@ -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",
@@ -11,8 +11,8 @@
"sources": {
"tanstack": {
"kind": "workspace",
- "revision": "7ac3c321ff253f51d2c7df7be6a63c6edb7b771f",
- "inputDigest": "sha256:44f03725e05260cba794012df73385ad7df1ccd9a7cd44ad2e560a05ebf682e7"
+ "revision": "02e24867f1699fa918fd49eaedfad64bc3f4e9e5",
+ "inputDigest": "sha256:790fc8c0e954afbba943d637d43b665739d2438d2cc6c341e81613baad327508"
},
"chartjs": {
"kind": "package",
@@ -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,
diff --git a/benchmarks/conformance/DEFINITION-COVERAGE-AUDIT.md b/benchmarks/conformance/DEFINITION-COVERAGE-AUDIT.md
index 856a0138..2aebf161 100644
--- a/benchmarks/conformance/DEFINITION-COVERAGE-AUDIT.md
+++ b/benchmarks/conformance/DEFINITION-COVERAGE-AUDIT.md
@@ -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. |
diff --git a/benchmarks/conformance/definition-coverage-roadmap.json b/benchmarks/conformance/definition-coverage-roadmap.json
index e4fc2ebc..5e86f3c8 100644
--- a/benchmarks/conformance/definition-coverage-roadmap.json
+++ b/benchmarks/conformance/definition-coverage-roadmap.json
@@ -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": [
@@ -2452,7 +2452,7 @@
"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."
},
{
@@ -2460,7 +2460,7 @@
"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."
}
]
@@ -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."
}
]
@@ -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."
}
]
@@ -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."
}
],
@@ -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."
}
]
diff --git a/benchmarks/conformance/definition-coverage-roadmap.test.ts b/benchmarks/conformance/definition-coverage-roadmap.test.ts
index 951440b9..4cd59f99 100644
--- a/benchmarks/conformance/definition-coverage-roadmap.test.ts
+++ b/benchmarks/conformance/definition-coverage-roadmap.test.ts
@@ -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)
}
diff --git a/benchmarks/conformance/previews/87-echarts-synchronized-cursors.svg b/benchmarks/conformance/previews/87-echarts-synchronized-cursors.svg
index db67340a..39a29e85 100644
--- a/benchmarks/conformance/previews/87-echarts-synchronized-cursors.svg
+++ b/benchmarks/conformance/previews/87-echarts-synchronized-cursors.svg
@@ -1 +1 @@
-
+
diff --git a/benchmarks/conformance/previews/manifest.json b/benchmarks/conformance/previews/manifest.json
index 8154f55d..5f0cc46f 100644
--- a/benchmarks/conformance/previews/manifest.json
+++ b/benchmarks/conformance/previews/manifest.json
@@ -2,7 +2,7 @@
"schemaVersion": 1,
"width": 288,
"height": 192,
- "sourceHash": "f71b56214bc650eab205bd970fb5c9ddabae61717dd5b6378f85a1514081441d",
+ "sourceHash": "61107a358d4bc33d970663907eb733cf5babfa82a20b18abe4fbcc5e455fee3f",
"assets": [
{
"id": "01-line-gaps",
@@ -386,8 +386,8 @@
},
{
"id": "87-echarts-synchronized-cursors",
- "sha256": "827f8aa0a720d26a538ac69f7781e7326d34d40348b31e46d3fd85bb1a859b10",
- "bytes": 8113
+ "sha256": "b801e38c12e28147beba54e0a3b6dcb123d1d49463620b8758ef429ce2478119",
+ "bytes": 7985
},
{
"id": "88-echarts-free-cursor",
diff --git a/docs/comparison.md b/docs/comparison.md
index a9abfa06..46102d37 100644
--- a/docs/comparison.md
+++ b/docs/comparison.md
@@ -12,14 +12,14 @@ turning untested behavior into a checkmark.
| Library | Package | Measured source |
| -------------------------------------------------------------------------------------- | -------------------- | ------------------- |
-| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `7ac3c32` |
+| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `02e2486` |
| [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 `7ac3c32`.
+at page render time. The measured TanStack workspace revision is `02e2486`.
## Capability matrix
@@ -106,7 +106,7 @@ Vega-Lite, AG Charts, and uPlot main exports were read from Bundlephobia on July
| Library | Bundle size | React externalized | Evidence |
| ------------------ | -------------------------------------- | -----------------: | ---------------------------------------------------------- |
-| TanStack Charts | 37.32–43.28 KiB | — | Controlled suite |
+| TanStack Charts | 37.46–43.41 KiB | — | Controlled suite |
| D3 | 90 KB gzip | — | External main export |
| Chart.js | 44.70–58.21 KiB | — | Controlled suite |
| Apache ECharts | 153.10–173.18 KiB | — | Controlled suite |
diff --git a/docs/framework/angular/adapter.md b/docs/framework/angular/adapter.md
index 82ec6d43..8e3919d3 100644
--- a/docs/framework/angular/adapter.md
+++ b/docs/framework/angular/adapter.md
@@ -32,17 +32,17 @@ standalone component ships as a partial-compiled Angular package.
## Lifecycle
`ngOnChanges` creates or updates one shared adapter controller.
-`ngAfterViewInit` mounts it into the prerendered surface, and `ngOnDestroy`
-cleans it up. Replace the complete `options` value when chart state changes;
-mutating the existing object does not produce an `OnPush` input change.
-Callbacks such as `onFocusChange` are functions inside `options`, not Angular
-outputs.
+Angular's `afterNextRender` mounts it into the prerendered surface in the
+browser, and `ngOnDestroy` cleans it up. Replace the complete `options` value
+when chart state changes; mutating the existing object does not produce an
+`OnPush` input change. Callbacks such as `onFocusChange` are functions inside
+`options`, not Angular outputs.
## Browser and server status
-The verified package contract covers browser mount, immutable updates, and
-teardown. Angular application SSR and hydration are not yet part of the
-adapter's tested public contract.
+The verified package contract covers complete SVG server rendering through
+Angular's `renderApplication`, browser mount, immutable updates, and teardown.
+Angular hydration is not yet part of the adapter's tested public contract.
## Presentation and rendering
diff --git a/packages/angular-charts/package.json b/packages/angular-charts/package.json
index 3929e0cd..4023fec6 100644
--- a/packages/angular-charts/package.json
+++ b/packages/angular-charts/package.json
@@ -31,6 +31,7 @@
"@angular/core": "^22.0.2",
"@angular/platform-browser": "^22.0.2",
"@angular/platform-browser-dynamic": "^22.0.2",
+ "@angular/platform-server": "^22.0.2",
"ng-packagr": "^22.0.0"
},
"publishConfig": {
diff --git a/packages/angular-charts/src/Chart.ssr.test.ts b/packages/angular-charts/src/Chart.ssr.test.ts
new file mode 100644
index 00000000..30aa476b
--- /dev/null
+++ b/packages/angular-charts/src/Chart.ssr.test.ts
@@ -0,0 +1,50 @@
+import '@angular/compiler'
+import { Component } from '@angular/core'
+import { bootstrapApplication } from '@angular/platform-browser'
+import { renderApplication } from '@angular/platform-server'
+import { describe, expect, it } from 'vitest'
+import { defineChart, lineY } from '@tanstack/charts'
+import { scaleLinear } from 'd3-scale'
+import { Chart } from './index'
+import type { ChartOptions } from './index'
+
+const rows = [
+ { id: 'a', x: 0, y: 2 },
+ { id: 'b', x: 1, y: 4 },
+]
+const definition = defineChart({
+ marks: [lineY(rows, { x: 'x', y: 'y', key: 'id' })],
+ x: { scale: scaleLinear().domain([0, 1]) },
+ y: { scale: scaleLinear().domain([0, 4]) },
+})
+
+@Component({
+ selector: 'test-server-chart',
+ standalone: true,
+ imports: [Chart],
+ template: '