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
21 changes: 21 additions & 0 deletions .changeset/trim-charttype-schema.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
---
"@objectstack/spec": major
---

BREAKING: `ChartTypeSchema` drops 8 variant types that only rendered as their
base chart, so the taxonomy now advertises only families the renderer draws
distinctly.

Removed: `grouped-bar`, `stacked-bar`, `bi-polar-bar` (→ bar — no multi-series
grouping/stacking), `stacked-area` (→ area), `step-line`, `spline` (→ line),
`pyramid` (→ funnel), `bubble` (→ scatter — no size encoding).

Kept: bar / horizontal-bar / column, line / area, pie / donut / funnel, scatter,
treemap / sankey, radar, table / pivot, and the single-value performance family
(metric / kpi / gauge / solid-gauge / bullet — these render an honest value
today and gain a dial when a gauge renderer lands).

Migration: a widget/series using a removed type should switch to its base
(`stacked-bar`→`bar`, `spline`→`line`, `pyramid`→`funnel`, `bubble`→`scatter`,
etc.). These can return via an opt-in renderer once a real renderer + data model
backs them.
2 changes: 1 addition & 1 deletion .objectui-sha
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
76094e0d4ed79b8732ba9879c75aa5ab8283180d
ec530a92ba2cdb6dbb0a1f5ee3b800503296e2f1
12 changes: 2 additions & 10 deletions content/docs/references/ui/chart.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -69,7 +69,7 @@ const result = ChartAnnotation.parse(data);

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'grouped-bar' \| 'stacked-bar' \| 'bi-polar-bar' \| 'line' \| 'area' \| 'stacked-area' \| 'step-line' \| 'spline' \| 'pie' \| 'donut' \| 'funnel' \| 'pyramid' \| 'scatter' \| 'bubble' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | ✅ | |
| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| 'funnel' \| 'scatter' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | ✅ | |
| **title** | `string` | optional | Chart title |
| **subtitle** | `string` | optional | Chart subtitle |
| **description** | `string` | optional | Accessibility description |
Expand DownExpand Up@@ -109,7 +109,7 @@ const result = ChartAnnotation.parse(data);
| :--- | :--- | :--- | :--- |
| **name** | `string` | ✅ | Field name or series identifier |
| **label** | `string` | optional | Series display label |
| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'grouped-bar' \| 'stacked-bar' \| 'bi-polar-bar' \| 'line' \| 'area' \| 'stacked-area' \| 'step-line' \| 'spline' \| 'pie' \| 'donut' \| 'funnel' \| 'pyramid' \| 'scatter' \| 'bubble' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | optional | Override chart type for this series |
| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| 'funnel' \| 'scatter' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | optional | Override chart type for this series |
| **color** | `string` | optional | Series color (hex/rgb/token) |
| **stack** | `string` | optional | Stack identifier to group series |
| **yAxis** | `Enum<'left' \| 'right'>` | ✅ | Bind to specific Y-Axis |
Expand All@@ -127,20 +127,12 @@ const result = ChartAnnotation.parse(data);
* `bar`
* `horizontal-bar`
* `column`
* `grouped-bar`
* `stacked-bar`
* `bi-polar-bar`
* `line`
* `area`
* `stacked-area`
* `step-line`
* `spline`
* `pie`
* `donut`
* `funnel`
* `pyramid`
* `scatter`
* `bubble`
* `treemap`
* `sankey`
* `gauge`
Expand Down
22 changes: 8 additions & 14 deletions examples/app-showcase/test/coverage.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,20 +49,14 @@ describe('showcase coverage (introspected against the spec)', () => {
});

it('covers every distinctly-renderable ChartType', () => {
// The Chart Gallery demonstrates only chart families the renderer draws
// DISTINCTLY — advertising a type that renders as something else (a "sankey"
// that draws bars) is worse than not offering it. The families below have no
// distinct renderer yet and fall back to a near-relative, so the showcase
// intentionally does not duplicate them: grouped/stacked/bi-polar bars (→bar),
// stacked-area (→area), step-line/spline (→line), pyramid (→funnel), bubble
// (→scatter), and the dial-less performance variants kpi/gauge/solid-gauge/
// bullet (→ the same KPI value as `metric`). Follow-up: trim these from
// `ChartTypeSchema` so spec ↔ renderer ↔ showcase stay in lockstep.
const FALLBACK_ONLY = new Set([
'grouped-bar', 'stacked-bar', 'bi-polar-bar', 'stacked-area', 'step-line',
'spline', 'pyramid', 'bubble', 'kpi', 'gauge', 'solid-gauge', 'bullet',
]);
const expected = enumValues(ui.ChartTypeSchema).filter((t) => !FALLBACK_ONLY.has(t));
// The fallback-only VARIANTS (grouped/stacked/bi-polar bar, stacked-area,
// step-line, spline, pyramid, bubble) were removed from `ChartTypeSchema`, so
// the enum now lists only families that render. The remaining exception is
// the performance group: `metric` represents the single-value KPI, and
// `kpi`/`gauge`/`solid-gauge`/`bullet` render the SAME value today (no dial),
// so the gallery demonstrates `metric` once rather than duplicating them.
const SAME_AS_METRIC = new Set(['kpi', 'gauge', 'solid-gauge', 'bullet']);
const expected = enumValues(ui.ChartTypeSchema).filter((t) => !SAME_AS_METRIC.has(t));
const used = new Set<string>();
for (const w of ChartGalleryDashboard.widgets ?? []) if (w.type) used.add(w.type);
expectFullCoverage('ChartType', expected, used);
Expand Down
23 changes: 17 additions & 6 deletions packages/spec/src/ui/chart.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,16 +8,16 @@ import {

describe('ChartTypeSchema', () => {
it('should accept all comparison chart types', () => {
const types = ['bar', 'horizontal-bar', 'column', 'grouped-bar', 'stacked-bar'] as const;
const types = ['bar', 'horizontal-bar', 'column'] as const;

types.forEach(type => {
expect(() => ChartTypeSchema.parse(type)).not.toThrow();
});
});

it('should accept all trend chart types', () => {
const types = ['line', 'area', 'stacked-area', 'step-line'] as const;
const types = ['line', 'area'] as const;

types.forEach(type => {
expect(() => ChartTypeSchema.parse(type)).not.toThrow();
});
Expand All@@ -32,8 +32,8 @@ describe('ChartTypeSchema', () => {
});

it('should accept all relationship chart types', () => {
const types = ['scatter', 'bubble'] as const;
const types = ['scatter'] as const;

types.forEach(type => {
expect(() => ChartTypeSchema.parse(type)).not.toThrow();
});
Expand DownExpand Up@@ -72,6 +72,17 @@ describe('ChartTypeSchema', () => {
});
});

it('should reject variant types that only render as their base chart', () => {
// Removed: each fell back to a base family the renderer already draws, so
// advertising them lied about the output (see the taxonomy NOTE in chart.zod).
const fallbackOnly = ['grouped-bar', 'stacked-bar', 'bi-polar-bar', 'stacked-area',
'step-line', 'spline', 'pyramid', 'bubble'] as const;

fallbackOnly.forEach(type => {
expect(() => ChartTypeSchema.parse(type)).toThrow();
});
});

it('should accept all tabular chart types', () => {
const types = ['table', 'pivot'] as const;

Expand Down
42 changes: 22 additions & 20 deletions packages/spec/src/ui/chart.zod.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,32 +20,25 @@ export const ChartTypeSchema = lazySchema(() => z.enum([
'bar',
'horizontal-bar',
'column',
'grouped-bar',
'stacked-bar',
'bi-polar-bar',


// Trend
'line',
'area',
'stacked-area',
'step-line',
'spline',


// Distribution
'pie',
'donut',
'funnel',
'pyramid',


// Relationship
'scatter',
'bubble',


// Composition
'treemap',
'sankey',

// Performance
// Performance (single value — metric/kpi render a number; gauge/solid-gauge/
// bullet are honest single-value variants pending a real dial/target renderer)
'gauge',
'solid-gauge',
'metric',
Expand All@@ -60,13 +53,22 @@ export const ChartTypeSchema = lazySchema(() => z.enum([
'pivot',
]));

// NOTE: chart families that require data shapes the platform does not model
// (OHLC for candlestick/stock, per-record distributions for box-plot/violin),
// geographic data (choropleth/bubble-map/gl-map), or dependencies the default
// Recharts renderer lacks (sunburst, heatmap, word-cloud, waterfall) were
// removed from this taxonomy: advertising a chart type the renderer can't draw
// is worse than not offering it. They can return via an opt-in renderer plugin
// once there is real demand and a data model to back them.
// NOTE: the taxonomy lists only chart families the default Recharts renderer
// draws DISTINCTLY. Two groups are intentionally absent:
//
// 1. Families requiring data/dependencies the platform does not model — OHLC
// (candlestick/stock), per-record distributions (box-plot/violin), geo
// (choropleth/bubble-map/gl-map), or extra renderers (sunburst, heatmap,
// word-cloud, waterfall).
// 2. VARIANTS that only render as their base chart, so advertising them lies
// about the output: grouped-bar / stacked-bar / bi-polar-bar (→ bar, no
// multi-series grouping/stacking), stacked-area (→ area), step-line / spline
// (→ line), pyramid (→ funnel), bubble (→ scatter, no size encoding).
//
// Both can return via an opt-in renderer once there is a real renderer and a
// data model to back them. (`metric`/`kpi` are kept as honest single-value
// synonyms; `gauge`/`solid-gauge`/`bullet` render a value today and gain a dial
// when a gauge renderer lands.)

export type ChartType = z.infer<typeof ChartTypeSchema>;

Expand Down