Skip to content

Commit a71ede6

Browse files
serpentbladeclaude
andcommitted
feat(31-03): chartjs per-type components (8) + /auto entry (A/G2 + B)
codegen generalized from "1 source -> 6 leaves" to "1 source + 8 variant specs -> 6 leaves, each exporting the generic Chart + Line/Bar/Pie/Doughnut/PolarArea/ Radar/Scatter/Bubble". Each variant is a codegen-transformed FULL-source component (bounded, fail-loud transform of Chart.rozie: remove the `type` prop + its $watch, pin `type`, narrow+add registration, rename) — so every typed component carries the FULL surface (props-type / 3 events / 8-verb handle / tooltip+fallback slots) uniformly across all 6 targets with ZERO cross-framework forwarding ceremony (strictly richer than thin wrappers, the refinement logged in 31-SPEC). Each variant registers only its own controller set (tree-shakable). Per-leaf `/auto` entry (`@rozie-ui/chartjs-<fw>/auto`) registers ...registerables + re-exports the barrel — the kitchen-sink convenience. All 6 leaves now carry a barrel index.ts (source leaves gained one; `.` export repointed). Bundled react/solid/lit add a `src/auto.ts` tsdown entry + `./auto` package export. Tree-shaking: generic Chart (consumer-registers, 31-02) + source-leaf per-type imports tree-shake natively; bundled-leaf typed components currently share one chunk (documented; per-variant chunking tracked). Guide gains a Registration & per-type components section; comparison-doc cells flipped to ✓ (per-type + tree-shakable registration) + datasetIdKey/fallback caveats closed. Gates: codegen ENFORCING 11-row PASS; all 6×9 components compile 0-err; 3 bundled leaves build (index+auto, dts) + typecheck green; pack dry-runs ship /auto+barrel+ variants; engine-examples 1382; docs 110 anchors/0 broken. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 18f9be4 commit a71ede6

79 files changed

Lines changed: 18890 additions & 165 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/guide/chartjs-comparison.md

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ of absence.)
3030

3131
| Wrapper | Frameworks | Latest published | Framework support | Structured events | Imperative handle | HTML-tooltip slot | Per-type components | Selective (tree-shakable) registration |
3232
| --- | --- | --- | --- | :---: | :---: | :---: | :---: | :---: |
33-
| **[Rozie @rozie-ui/chartjs](/guide/chartjs)** | **6 — React + Vue + Svelte + Angular + Solid + Lit** | this repo (2026-06) | R18+ / V3.4+ / Sv5 / **Ng19+ signals** / Solid / Lit |**3 uniform** (`click`/`hover`/`datasetClick`, structured, composed) on all 6 |**uniform `$expose`** (8 verbs) on all 6 |**portal slot** on all 6 | generic `Chart` only *(deferred — see gaps)* | ✗ forces `registerables` *(gap — see below)* |
33+
| **[Rozie @rozie-ui/chartjs](/guide/chartjs)** | **6 — React + Vue + Svelte + Angular + Solid + Lit** | this repo (2026-06) | R18+ / V3.4+ / Sv5 / **Ng19+ signals** / Solid / Lit |**3 uniform** (`click`/`hover`/`datasetClick`, structured, composed) on all 6 |**uniform `$expose`** (8 verbs) on all 6 |**portal slot** on all 6 | **8 typed components** + generic `Chart`, all 6 | ✓ consumer-registers + `/auto` entry (per-type tree-shakes on source leaves) |
3434
| [react-chartjs-2](https://react-chartjs-2.js.org/) | React | **5.3.1** · 2025-10 | React 16.8 – **19** | ~ `options.onClick` + `getElement*AtEvent` helpers (no React events) |`ref` → Chart.js instance | ✗ external-handler only (no React slot) | ✓ 8 typed + generic `Chart` | ✓ typed components auto-register their controller |
3535
| [vue-chartjs](https://vue-chartjs.org/) | Vue 3 | **5.3.3** · 2025 | Vue 3 (3.x+) | ✗ emits no Vue events |`ref.chart` → instance | ✗ external-handler only (canvas-fallback slot only) | ✓ 8 typed + generic + `createTypedChart` | ✓ manual `ChartJS.register(...)` |
3636
| [ng2-charts](https://valor-software.com/ng2-charts) | Angular | **10.0.0** · 2026-03 *(v8 = Ng19)* | Angular 17 – **21** *(no signals — `@Input`/`OnChanges`)* |`chartClick` / `chartHover` (2, Angular only) |`ViewChild(BaseChartDirective).chart` | ✗ no `ng-template` tooltip | ~ one `canvas[baseChart]` directive (`type` input) |`provideCharts(...)` selective |
@@ -128,38 +128,24 @@ comparison credible, and it doubles as Rozie's own roadmap.
128128
leading it. Rozie's advantage on React/Vue/Angular/Svelte is the *uniform
129129
cross-framework surface* and one source, not "more current."
130130

131-
- **Per-type components (`<Line>`, `<Bar>`, …) — react/vue/svelte/solid ship them;
132-
Rozie does not (yet).** react-chartjs-2, vue-chartjs, svelte-chartjs, and
133-
solid-chartjs all export eight typed convenience components, so a consumer writes
134-
`<Bar data={…} />` rather than `<Chart type="bar" data={…} />`. Rozie v1 ships
135-
only the generic `Chart` (the `type` prop covers the whole controller set). This
136-
is a real ergonomic gap and a tracked follow-up — see the
137-
[Chart.js showcase](/guide/chartjs) and the project's gap-closure plan.
138-
139-
- **Selective (tree-shakable) controller registration — the wrappers support it;
140-
Rozie v1 does not.** Chart.js v3+ is tree-shakable: react-chartjs-2's typed
141-
components register only their own controller, and vue/svelte/ng2 let the
142-
consumer `register(...)` (or `provideCharts(...)`) exactly the controllers,
143-
elements, scales, and plugins they use — keeping the bundle minimal. Rozie's
144-
generic `Chart` calls `Chart.register(...registerables)` unconditionally (the
145-
"kitchen sink") so the `type` prop can switch to any kind at runtime, which
146-
means a consumer who only renders line charts still ships every controller.
147-
Trading bundle size for runtime genericity is a deliberate v1 choice, and the
148-
fix is coupled to per-type components (each could register only its controller)
149-
— both are on the gap-closure plan.
150-
151-
- **`datasetIdKey` dataset diffing — react/vue have it; Rozie matches by index.**
152-
react-chartjs-2 and vue-chartjs expose a `datasetIdKey` prop so datasets are
153-
diffed by a stable key across updates (guarding the "first dataset copied over
154-
the others" hazard). Rozie reconciles datasets by array index, which is correct
155-
for the common append/replace cases but does not yet offer a keyed-diff opt-in.
156-
Tracked.
157-
158-
- **`fallbackContent` a11y — react/vue/solid render fallback inside the canvas.**
159-
Those wrappers let you render arbitrary fallback content inside the `<canvas>`
160-
for assistive tech. Rozie surfaces an `ariaLabel` prop today but not a
161-
fallback-content slot; a non-portal a11y fallback slot is a small tracked
162-
addition.
131+
- **Per-type components and selective registration — now closed (one bundled-leaf
132+
nuance remains).** Rozie's first cut shipped only the generic `Chart` and
133+
force-registered every controller. Both are resolved: the generic `Chart` no
134+
longer auto-registers (the consumer registers what they use, or imports the
135+
`/auto` kitchen-sink entry), and each package now also exports the eight
136+
[per-type components](/guide/chartjs#per-type-components)`Line`/`Bar`/…/`Bubble`
137+
— each registering only its own controller set. *Remaining nuance:* on the
138+
bundled React/Solid/Lit packages the typed components currently share one chunk,
139+
so importing one pulls the others' registration; the generic-`Chart`
140+
consumer-registration path is the recommended one there, and per-variant chunking
141+
on the bundled packages is a tracked optimization. The source-shipped
142+
Vue/Svelte/Angular packages tree-shake per-type imports natively.
143+
144+
- **`datasetIdKey` and a11y `fallback` — now covered.** The `datasetIdKey` prop
145+
(default `'label'`) matches datasets by a stable key across updates (with index
146+
fallback), and a non-portal [`fallback` slot](/guide/chartjs#slots) renders a11y
147+
content inside the `<canvas>` (alongside the `ariaLabel` prop) — closing the
148+
react/vue parity gap on both.
163149

164150
- **Single-framework ergonomics are not the contest.** The matrix scores
165151
out-of-the-box, cross-framework capability. For a single-React or single-Vue

docs/guide/chartjs.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,33 @@ npm i @rozie-ui/chartjs-react chart.js
2929

3030
Anything the curated prop surface doesn't special-case (scales, legends, custom plugins, per-dataset styling) comes through the `data`/`options` props — Chart.js's own config shapes — and the first-class `:plugins` passthrough for per-instance plugins. The per-leaf READMEs and the **Props** table below are generated from the same IR parse of `Chart.rozie`, so they cannot drift from the compiled output — the package's `codegen.mjs` asserts the structural columns of this page against `ir.props` on every run.
3131

32+
## Registration & per-type components
33+
34+
Chart.js v3+ is **tree-shakable**: it ships with no controllers/elements/scales pre-registered. The generic `Chart` follows that model — it does **not** auto-register, so an app that only renders line charts doesn't bundle every controller. Register what you use once at startup:
35+
36+
```ts
37+
import { Chart, LineController, LineElement, PointElement, LinearScale, CategoryScale } from 'chart.js';
38+
Chart.register(LineController, LineElement, PointElement, LinearScale, CategoryScale);
39+
```
40+
41+
…or, for the kitchen sink, import the package's **`/auto`** entry (or Chart.js's own `chart.js/auto`), which registers everything:
42+
43+
```ts
44+
import { Chart } from '@rozie-ui/chartjs-react/auto'; // registers ...registerables
45+
```
46+
47+
### Per-type components
48+
49+
Each package also exports **eight per-type components**`Line`, `Bar`, `Pie`, `Doughnut`, `PolarArea`, `Radar`, `Scatter`, `Bubble` — so you can write `<Bar :data="…" />` instead of `<Chart type="bar" :data="…" />`. Each one pins its `type` and **registers only its own controller set**, so importing it needs no manual registration and is tree-shakable by construction (on the source-shipped Vue/Svelte/Angular packages, importing `Bar` pulls only the bar code). A per-type component carries the *same* surface as the generic `Chart` minus the `type` prop — the full props / 3 events / 8-verb handle / `tooltip` + `fallback` slots:
50+
51+
```tsx
52+
import { Bar } from '@rozie-ui/chartjs-react'; // no manual register() needed
53+
54+
<Bar data={data} options={options} onClick={(p) => console.log(p.elements)} />;
55+
```
56+
57+
> **Bundle note:** on the bundled React/Solid/Lit packages the per-type components currently share one chunk, so importing one typed component pulls the others' registration too; the **generic `Chart` + selective registration** (above) is the recommended path when bundle size is critical there. The source-shipped Vue/Svelte/Angular packages tree-shake per-type imports natively. Per-variant chunking on the bundled packages is a tracked optimization.
58+
3259
## Quick start
3360

3461
`data` and `options` are Chart.js's own shapes; `type` picks the chart kind. The chart reconciles `data` changes into the live instance (mutating `chart.data` in place and calling `chart.update()`) so series tween point-to-point without a remount.

packages/ui/chartjs/packages/angular/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ export class DemoComponent {
3030
}
3131
```
3232

33+
## Registration & per-type components
34+
35+
Chart.js v3+ is tree-shakable: the generic `Chart` does **not** auto-register controllers, so register what you use —
36+
37+
```ts
38+
import { Chart, LineController, LineElement, PointElement, LinearScale, CategoryScale } from 'chart.js';
39+
Chart.register(LineController, LineElement, PointElement, LinearScale, CategoryScale);
40+
```
41+
42+
— or import the kitchen-sink `/auto` entry (`@rozie-ui/chartjs-angular/auto`, or `import 'chart.js/auto'`) which registers everything.
43+
44+
Or use a **per-type component** — each pins its `type` and registers only its own controller set (so importing one is tree-shakable), with the same props/events/handle as the generic `Chart` (minus `type`): `Line`, `Bar`, `Pie`, `Doughnut`, `PolarArea`, `Radar`, `Scatter`, `Bubble`.
45+
3346
## Props
3447

3548
| Name | Type | Default | Two-way (model) | Required |

packages/ui/chartjs/packages/angular/package.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@
2727
},
2828
"exports": {
2929
".": {
30-
"types": "./src/Chart.ts",
31-
"import": "./src/Chart.ts",
32-
"default": "./src/Chart.ts"
30+
"types": "./src/index.ts",
31+
"import": "./src/index.ts",
32+
"default": "./src/index.ts"
33+
},
34+
"./auto": {
35+
"types": "./src/auto.ts",
36+
"import": "./src/auto.ts",
37+
"default": "./src/auto.ts"
3338
}
3439
},
3540
"files": [

0 commit comments

Comments
 (0)