@aiaiai-pt/design-system 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,6 +54,11 @@
54
54
  valueHeader = "Value",
55
55
  /** @type {string} BCP-47 locale for number formatting. */
56
56
  locale = "en",
57
+ /** @type {"bar" | "line" | "donut"} Chart kind (#176 Tier 1). `bar` is the
58
+ * horizontal categorical bar; `line` plots the same series as a value line
59
+ * over the category axis; `donut` is a ring pie. The data table below is
60
+ * the accessible source of truth for every kind. */
61
+ kind = "bar",
57
62
  /** @type {string} CSS block-size for the chart canvas. */
58
63
  height = "20rem",
59
64
  /** @type {string} */
@@ -90,9 +95,73 @@
90
95
  const textSecondary = token("--color-text-secondary", "#6b7280");
91
96
  const border = token("--color-border", "#e5e7eb");
92
97
 
93
- // ECharts plots the category axis bottom-up; reverse so the highest value
94
- // sits at the top (matching ResultsChart's top-down order). `items` is
95
- // already sorted desc by the consumer.
98
+ // Donut: a ring pie. No axes; the slice palette derives from the accent
99
+ // (alpha ramp) so it stays on-theme without a hardcoded colour list.
100
+ if (kind === "donut") {
101
+ const palette = items.map((_, i) => {
102
+ const alpha = Math.max(0.35, 1 - i * 0.12);
103
+ return `color-mix(in srgb, ${accent} ${Math.round(alpha * 100)}%, transparent)`;
104
+ });
105
+ return {
106
+ animation: false,
107
+ tooltip: {
108
+ trigger: "item",
109
+ /** @param {{ name: string, value: number, percent: number }} p */
110
+ formatter: (p) => `${p.name}: ${fmt(p.value)} (${p.percent}%)`,
111
+ },
112
+ color: palette,
113
+ series: [
114
+ {
115
+ type: "pie",
116
+ radius: ["45%", "72%"],
117
+ data: items.map((it) => ({ name: it.label, value: it.value })),
118
+ label: { color: textPrimary },
119
+ labelLine: { lineStyle: { color: border } },
120
+ },
121
+ ],
122
+ };
123
+ }
124
+
125
+ // Line: value over the category axis, in the consumer's order (desc by
126
+ // value). Shares the same accent + token theming as the bar.
127
+ if (kind === "line") {
128
+ return {
129
+ animation: false,
130
+ grid: { left: 8, right: 16, top: 8, bottom: 8, containLabel: true },
131
+ tooltip: {
132
+ trigger: "axis",
133
+ /** @param {{ name: string, value: number }[]} p */
134
+ formatter: (p) => `${p[0]?.name}: ${fmt(p[0]?.value)}`,
135
+ },
136
+ xAxis: {
137
+ type: "category",
138
+ data: items.map((it) => it.label),
139
+ axisLabel: { color: textPrimary },
140
+ axisLine: { lineStyle: { color: border } },
141
+ axisTick: { show: false },
142
+ },
143
+ yAxis: {
144
+ type: "value",
145
+ axisLabel: { color: textSecondary, formatter: (/** @type {number} */ v) => fmt(v) },
146
+ axisLine: { lineStyle: { color: border } },
147
+ splitLine: { lineStyle: { color: border } },
148
+ },
149
+ series: [
150
+ {
151
+ type: "line",
152
+ data: items.map((it) => it.value),
153
+ itemStyle: { color: accent },
154
+ lineStyle: { color: accent },
155
+ symbolSize: 7,
156
+ smooth: false,
157
+ },
158
+ ],
159
+ };
160
+ }
161
+
162
+ // Bar (default). ECharts plots the category axis bottom-up; reverse so the
163
+ // highest value sits at the top (matching ResultsChart's top-down order).
164
+ // `items` is already sorted desc by the consumer.
96
165
  const ordered = [...items].reverse();
97
166
 
98
167
  return {
@@ -150,6 +219,8 @@
150
219
 
151
220
  core.use([
152
221
  charts.BarChart,
222
+ charts.LineChart,
223
+ charts.PieChart,
153
224
  components.GridComponent,
154
225
  components.TooltipComponent,
155
226
  renderers.CanvasRenderer,
@@ -187,7 +258,10 @@
187
258
  // touch reactive deps so the effect re-runs when they change
188
259
  void items;
189
260
  void locale;
190
- if (_chart) _chart.setOption(buildOption());
261
+ void kind;
262
+ // A kind switch changes which axes/series exist; replace (not merge) the
263
+ // option so stale axis components from the previous kind are cleared.
264
+ if (_chart) _chart.setOption(buildOption(), true);
191
265
  });
192
266
  </script>
193
267
 
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import EChartWidget from "./EChartWidget.svelte";
3
+ import type { WidgetProps } from "./types";
4
+
5
+ // `donut-chart` registry key (#176 Tier 1). Thin wrapper binding the ECharts
6
+ // `kind` to a ring pie — the registry maps this key here. Same aggregate data
7
+ // path + a11y data table as the bar/line.
8
+ let p: WidgetProps = $props();
9
+ </script>
10
+
11
+ <EChartWidget {...p} kind="donut" />
@@ -0,0 +1,4 @@
1
+ import type { WidgetProps } from "./types";
2
+ declare const DonutChartWidget: import("svelte").Component<WidgetProps, {}, "">;
3
+ type DonutChartWidget = ReturnType<typeof DonutChartWidget>;
4
+ export default DonutChartWidget;
@@ -11,7 +11,12 @@
11
11
  // is never the only encoding). Same data path as ResultsChartWidget: reads
12
12
  // the `{ items }` rows and projects `{ label, value }` via `toRankedItems`,
13
13
  // so NO resolve-data / provider change is needed. Soft-empty on no rows.
14
- let { data, props, ownsH1, locale }: WidgetProps = $props();
14
+ // `kind` is bound by the registry wrapper (line-chart / donut-chart), NOT by
15
+ // the dispatcher (which renders this widget with the standard WidgetProps and
16
+ // no kind → the `chart` key stays the ECharts bar). #176 Tier 1.
17
+ let { data, props, ownsH1, locale, kind = "bar" }: WidgetProps & {
18
+ kind?: "bar" | "line" | "donut";
19
+ } = $props();
15
20
 
16
21
  const rows = $derived(
17
22
  data && typeof data === "object" && Array.isArray((data as { items?: unknown }).items)
@@ -63,6 +68,7 @@
63
68
  {caption}
64
69
  {labelHeader}
65
70
  {valueHeader}
71
+ {kind}
66
72
  locale={locale ?? "en"}
67
73
  />
68
74
  </section>
@@ -0,0 +1,12 @@
1
+ <script lang="ts">
2
+ import EChartWidget from "./EChartWidget.svelte";
3
+ import type { WidgetProps } from "./types";
4
+
5
+ // `line-chart` registry key (#176 Tier 1). Thin wrapper that binds the ECharts
6
+ // `kind` the dispatcher can't pass — the registry maps this key to this
7
+ // component, which renders the shared EChart widget as a line. Same aggregate
8
+ // data path + a11y data table as the bar.
9
+ let p: WidgetProps = $props();
10
+ </script>
11
+
12
+ <EChartWidget {...p} kind="line" />
@@ -0,0 +1,4 @@
1
+ import type { WidgetProps } from "./types";
2
+ declare const LineChartWidget: import("svelte").Component<WidgetProps, {}, "">;
3
+ type LineChartWidget = ReturnType<typeof LineChartWidget>;
4
+ export default LineChartWidget;
@@ -22,7 +22,9 @@ import {
22
22
  } from "./dispatch";
23
23
  import type { Block, OntologySchema, WidgetKind, WidgetProps } from "./types";
24
24
 
25
+ import DonutChartWidget from "./DonutChartWidget.svelte";
25
26
  import EChartWidget from "./EChartWidget.svelte";
27
+ import LineChartWidget from "./LineChartWidget.svelte";
26
28
  import ResultsChartWidget from "./ResultsChartWidget.svelte";
27
29
  import StatGridWidget from "./StatGridWidget.svelte";
28
30
 
@@ -69,6 +71,11 @@ const _entries: RegistryEntry<WidgetComponent>[] = [
69
71
  byKind("stat-grid", "kpi", StatGridWidget),
70
72
  byTypeOnKind("results-chart", "aggregate", ResultsChartWidget),
71
73
  byTypeOnKind("chart", "aggregate", EChartWidget),
74
+ // #176 Tier 1 — chart KINDS as registry entries, so the authoring `type`
75
+ // picker is a real chart picker. All three ECharts kinds share the same
76
+ // aggregate data path + a11y data table; only the rendered geometry differs.
77
+ byTypeOnKind("line-chart", "aggregate", LineChartWidget),
78
+ byTypeOnKind("donut-chart", "aggregate", DonutChartWidget),
72
79
  ];
73
80
 
74
81
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/design-system",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "Design system tokens and Svelte components for aiaiai products",
5
5
  "license": "MIT",
6
6
  "type": "module",