@aganzefelicite/responsekit-react 0.1.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.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # @aganzefelicite/responsekit-react
2
+
3
+ Render your AI backend's responses as interactive React UI. Point it at your backend and
4
+ it turns the standardized response contract (streamed as SSE or a single object) into
5
+ components — safely, and without ever crashing on unknown or invalid data.
6
+
7
+ - **Renders only** — never calls an AI model or generates responses.
8
+ - **Never crashes** — unknown block types / missing fields degrade to a safe fallback.
9
+ - **Safe by default** — AI text is GitHub-flavored Markdown with **no raw HTML**; data
10
+ values are escaped. No `dangerouslySetInnerHTML`.
11
+ - **Lean bundle** — tree-shakeable ESM, React as a peer dep; charts (Recharts) are
12
+ lazy-loaded into their own chunk.
13
+
14
+ > Full walkthrough: **[Adding ResponseKit to an existing project](../../docs/INTEGRATION.md)**.
15
+
16
+ ## Install
17
+
18
+ Not published to npm yet — install from a local build of this repo (`@responsekit/schema`
19
+ is bundled in, so it's a single tarball):
20
+
21
+ ```bash
22
+ # in the repo root
23
+ pnpm pack:local
24
+ # in your app
25
+ pnpm add /ABS/PATH/responsekit-react-0.0.0.tgz react react-dom
26
+ ```
27
+
28
+ ```ts
29
+ import "@aganzefelicite/responsekit-react/styles.css"; // optional default styling
30
+ ```
31
+
32
+ See [docs/INTEGRATION.md](../../docs/INTEGRATION.md) for `pnpm link` and publishing options.
33
+
34
+ ## Quick start
35
+
36
+ ```tsx
37
+ import { AiRenderer, AiStream, useChat } from "@aganzefelicite/responsekit-react";
38
+
39
+ // 1) Render a response you already have
40
+ <AiRenderer response={response} onAction={(a) => {}} />;
41
+
42
+ // 2) Stream one message
43
+ <AiStream baseUrl="" conversationId={id} message="How many open cases?" onAction={(a) => {}} />;
44
+
45
+ // 3) A whole conversation
46
+ const { turns, send, isStreaming, newConversation } = useChat({ baseUrl: "" });
47
+ ```
48
+
49
+ `baseUrl` is prepended to the API paths; `""` means same-origin (proxy `/api` to your
50
+ backend). The message endpoint is POST + `text/event-stream`; the SDK drives
51
+ `fetch` + `ReadableStream` internally (native `EventSource` can't POST).
52
+
53
+ ## API
54
+
55
+ **Components** — `AiRenderer`, `AiStream`
56
+ **Hooks** — `useAiStream`, `useChat`
57
+ **Registry** — `registerBlock`, `unregisterBlock`, `resolveBlockComponent`
58
+ **Default blocks** — `TextBlock`, `KpiBlock`, `ChartBlock`, `TableBlock`, `InsightBlock`,
59
+ `RecommendationBlock`, `FilterBlock`, `FallbackBlock`, `defaultBlockComponents`
60
+ **Conversation REST** — `createConversation`, `listConversations`, `getConversation`,
61
+ `renameConversation`, `deleteConversation`, `getMessages`
62
+ **Transport** — `streamMessage`, `messageUrl`
63
+ **Misc** — `Markdown`, `ErrorBoundary`, action types, and everything re-exported from
64
+ [`@responsekit/schema`](../schema) (types, validators, the stream reducer).
65
+
66
+ ## Overrides & custom blocks
67
+
68
+ ```tsx
69
+ // override built-ins for one render
70
+ <AiRenderer response={r} components={{ KPI: MyKpi, CHART: MyChart }} />;
71
+
72
+ // register a custom/unknown block type globally
73
+ import { registerBlock } from "@aganzefelicite/responsekit-react";
74
+ registerBlock({ type: "MAP", component: RwandaMap });
75
+ ```
76
+
77
+ Resolution order per block type: `components` prop → globally registered → built-in default
78
+ → graceful fallback.
79
+
80
+ ## Actions
81
+
82
+ Blocks emit intent through one `onAction(action)` callback (`DOWNLOAD`, `OPEN_LINK`,
83
+ `REFRESH`, `CUSTOM`, or host-defined). The SDK never runs business logic.
84
+
85
+ ## License
86
+
87
+ MIT
@@ -0,0 +1,153 @@
1
+ 'use strict';
2
+
3
+ var chunkD4WIPDH3_cjs = require('./chunk-D4WIPDH3.cjs');
4
+ var recharts = require('recharts');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ var PALETTE = [
8
+ "#2563eb",
9
+ "#16a34a",
10
+ "#d97706",
11
+ "#dc2626",
12
+ "#7c3aed",
13
+ "#0891b2",
14
+ "#db2777",
15
+ "#65a30d"
16
+ ];
17
+ function inferShape(data) {
18
+ const first = data[0] ?? {};
19
+ const keys = Object.keys(first);
20
+ const isNumericCol = (k) => data.some((row) => typeof row[k] === "number");
21
+ const xKey = keys.find((k) => !isNumericCol(k)) ?? keys[0] ?? "x";
22
+ const seriesKeys = keys.filter((k) => k !== xKey && isNumericCol(k));
23
+ return {
24
+ xKey,
25
+ seriesKeys: seriesKeys.length ? seriesKeys : keys.filter((k) => k !== xKey)
26
+ };
27
+ }
28
+ var HEIGHT = 300;
29
+ var color = (i) => PALETTE[i % PALETTE.length];
30
+ function ChartRenderer({ block }) {
31
+ const data = Array.isArray(block.data) ? block.data : [];
32
+ if (data.length === 0) return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "rk-empty", children: "No chart data." });
33
+ const { xKey, seriesKeys } = inferShape(data);
34
+ const type = block.chartType;
35
+ switch (type) {
36
+ case "LINE":
37
+ return /* @__PURE__ */ jsxRuntime.jsx(Frame, { children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, children: [
38
+ grid(),
39
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: xKey, tick: AXIS_TICK }),
40
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { tick: AXIS_TICK }),
41
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, {}),
42
+ seriesKeys.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {}) : null,
43
+ seriesKeys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Line, { type: "monotone", dataKey: k, stroke: color(i), strokeWidth: 2, dot: false }, k))
44
+ ] }) });
45
+ case "AREA":
46
+ case "STACKED_AREA":
47
+ return /* @__PURE__ */ jsxRuntime.jsx(Frame, { children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.AreaChart, { data, children: [
48
+ grid(),
49
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: xKey, tick: AXIS_TICK }),
50
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { tick: AXIS_TICK }),
51
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, {}),
52
+ seriesKeys.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {}) : null,
53
+ seriesKeys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsx(
54
+ recharts.Area,
55
+ {
56
+ type: "monotone",
57
+ dataKey: k,
58
+ stackId: type === "STACKED_AREA" ? "stack" : void 0,
59
+ stroke: color(i),
60
+ fill: color(i),
61
+ fillOpacity: 0.25
62
+ },
63
+ k
64
+ ))
65
+ ] }) });
66
+ case "BAR":
67
+ case "STACKED_BAR":
68
+ return /* @__PURE__ */ jsxRuntime.jsx(Frame, { children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data, children: [
69
+ grid(),
70
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: xKey, tick: AXIS_TICK }),
71
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { tick: AXIS_TICK }),
72
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, {}),
73
+ seriesKeys.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {}) : null,
74
+ seriesKeys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsx(
75
+ recharts.Bar,
76
+ {
77
+ dataKey: k,
78
+ stackId: type === "STACKED_BAR" ? "stack" : void 0,
79
+ fill: color(i)
80
+ },
81
+ k
82
+ ))
83
+ ] }) });
84
+ case "PIE":
85
+ case "DONUT": {
86
+ const valueKey = seriesKeys[0] ?? "value";
87
+ return /* @__PURE__ */ jsxRuntime.jsx(Frame, { children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { children: [
88
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, {}),
89
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {}),
90
+ /* @__PURE__ */ jsxRuntime.jsx(
91
+ recharts.Pie,
92
+ {
93
+ data,
94
+ dataKey: valueKey,
95
+ nameKey: xKey,
96
+ cx: "50%",
97
+ cy: "50%",
98
+ outerRadius: 110,
99
+ innerRadius: type === "DONUT" ? 60 : 0,
100
+ label: (entry) => chunkD4WIPDH3_cjs.formatValue(entry?.name),
101
+ children: data.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Cell, { fill: color(i) }, i))
102
+ }
103
+ )
104
+ ] }) });
105
+ }
106
+ case "SCATTER": {
107
+ const xNum = seriesKeys[0];
108
+ const yNum = seriesKeys[1] ?? seriesKeys[0];
109
+ return /* @__PURE__ */ jsxRuntime.jsx(Frame, { children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.ScatterChart, { children: [
110
+ grid(),
111
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: xNum ?? xKey, type: "number", tick: AXIS_TICK, name: xNum ?? xKey }),
112
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { dataKey: yNum, type: "number", tick: AXIS_TICK, name: yNum }),
113
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.ZAxis, { range: [60, 60] }),
114
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { cursor: { strokeDasharray: "3 3" } }),
115
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Scatter, { data, fill: color(0) })
116
+ ] }) });
117
+ }
118
+ // HEATMAP (and anything Recharts can't express) → a readable data preview.
119
+ default:
120
+ return /* @__PURE__ */ jsxRuntime.jsx(PreviewTable, { block, data });
121
+ }
122
+ }
123
+ var AXIS_TICK = { fontSize: 12 };
124
+ var grid = () => /* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: "#eee" });
125
+ function Frame({ children }) {
126
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rk-chart", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: HEIGHT, children }) });
127
+ }
128
+ function PreviewTable({
129
+ block,
130
+ data
131
+ }) {
132
+ const keys = Object.keys(data[0] ?? {});
133
+ const preview = data.slice(0, 8);
134
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rk-chart-fallback", "data-chart-type": block.chartType, children: [
135
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rk-chart-badge", children: [
136
+ block.chartType,
137
+ " \xB7 rendered as a table (no chart mapping)"
138
+ ] }),
139
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "rk-table rk-chart-preview", children: [
140
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: keys.map((k) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: k }, k)) }) }),
141
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: preview.map((row, i) => /* @__PURE__ */ jsxRuntime.jsx("tr", { children: keys.map((k) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: chunkD4WIPDH3_cjs.formatValue(row[k]) }, k)) }, i)) })
142
+ ] }),
143
+ data.length > preview.length ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "rk-chart-more", children: [
144
+ "+",
145
+ data.length - preview.length,
146
+ " more rows"
147
+ ] }) : null
148
+ ] });
149
+ }
150
+
151
+ module.exports = ChartRenderer;
152
+ //# sourceMappingURL=ChartRenderer-UJNU2VNH.cjs.map
153
+ //# sourceMappingURL=ChartRenderer-UJNU2VNH.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blocks/ChartRenderer.tsx"],"names":["jsx","jsxs","LineChart","XAxis","YAxis","Tooltip","Legend","Line","AreaChart","Area","BarChart","Bar","PieChart","Pie","formatValue","Cell","ScatterChart","ZAxis","Scatter","CartesianGrid","ResponsiveContainer"],"mappings":"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","file":"ChartRenderer-UJNU2VNH.cjs","sourcesContent":["import type { ReactElement } from \"react\";\nimport {\n ResponsiveContainer,\n LineChart,\n Line,\n BarChart,\n Bar,\n AreaChart,\n Area,\n PieChart,\n Pie,\n Cell,\n ScatterChart,\n Scatter,\n XAxis,\n YAxis,\n ZAxis,\n CartesianGrid,\n Tooltip,\n Legend,\n} from \"recharts\";\nimport type { ChartBlock as ChartBlockType } from \"@responsekit/schema\";\nimport { formatValue } from \"./util.js\";\n\n/**\n * Real chart adapter, loaded lazily (see `ChartBlock`) so Recharts lands in its own\n * chunk and never weighs down the main bundle. This is the single place the SDK is\n * coupled to a charting library — swap it for visx/nivo/etc. without touching anything\n * else.\n *\n * The backend sends generic rows (e.g. `{ status: \"ONGOING\", count: 10 }`), so we infer\n * the category/x key (first non-numeric column) and the numeric series from the data.\n */\n\nconst PALETTE = [\n \"#2563eb\",\n \"#16a34a\",\n \"#d97706\",\n \"#dc2626\",\n \"#7c3aed\",\n \"#0891b2\",\n \"#db2777\",\n \"#65a30d\",\n];\n\ninterface Inferred {\n xKey: string;\n seriesKeys: string[];\n}\n\nfunction inferShape(data: Record<string, unknown>[]): Inferred {\n const first = data[0] ?? {};\n const keys = Object.keys(first);\n const isNumericCol = (k: string) => data.some((row) => typeof row[k] === \"number\");\n const xKey = keys.find((k) => !isNumericCol(k)) ?? keys[0] ?? \"x\";\n const seriesKeys = keys.filter((k) => k !== xKey && isNumericCol(k));\n // Fallback: if nothing looked numeric, treat every non-x column as a series.\n return {\n xKey,\n seriesKeys: seriesKeys.length ? seriesKeys : keys.filter((k) => k !== xKey),\n };\n}\n\nconst HEIGHT = 300;\nconst color = (i: number) => PALETTE[i % PALETTE.length];\n\nexport default function ChartRenderer({ block }: { block: ChartBlockType }) {\n const data = Array.isArray(block.data) ? (block.data as Record<string, unknown>[]) : [];\n if (data.length === 0) return <p className=\"rk-empty\">No chart data.</p>;\n\n const { xKey, seriesKeys } = inferShape(data);\n const type = block.chartType;\n\n switch (type) {\n case \"LINE\":\n return (\n <Frame>\n <LineChart data={data}>\n {grid()}\n <XAxis dataKey={xKey} tick={AXIS_TICK} />\n <YAxis tick={AXIS_TICK} />\n <Tooltip />\n {seriesKeys.length > 1 ? <Legend /> : null}\n {seriesKeys.map((k, i) => (\n <Line key={k} type=\"monotone\" dataKey={k} stroke={color(i)} strokeWidth={2} dot={false} />\n ))}\n </LineChart>\n </Frame>\n );\n\n case \"AREA\":\n case \"STACKED_AREA\":\n return (\n <Frame>\n <AreaChart data={data}>\n {grid()}\n <XAxis dataKey={xKey} tick={AXIS_TICK} />\n <YAxis tick={AXIS_TICK} />\n <Tooltip />\n {seriesKeys.length > 1 ? <Legend /> : null}\n {seriesKeys.map((k, i) => (\n <Area\n key={k}\n type=\"monotone\"\n dataKey={k}\n stackId={type === \"STACKED_AREA\" ? \"stack\" : undefined}\n stroke={color(i)}\n fill={color(i)}\n fillOpacity={0.25}\n />\n ))}\n </AreaChart>\n </Frame>\n );\n\n case \"BAR\":\n case \"STACKED_BAR\":\n return (\n <Frame>\n <BarChart data={data}>\n {grid()}\n <XAxis dataKey={xKey} tick={AXIS_TICK} />\n <YAxis tick={AXIS_TICK} />\n <Tooltip />\n {seriesKeys.length > 1 ? <Legend /> : null}\n {seriesKeys.map((k, i) => (\n <Bar\n key={k}\n dataKey={k}\n stackId={type === \"STACKED_BAR\" ? \"stack\" : undefined}\n fill={color(i)}\n />\n ))}\n </BarChart>\n </Frame>\n );\n\n case \"PIE\":\n case \"DONUT\": {\n const valueKey = seriesKeys[0] ?? \"value\";\n return (\n <Frame>\n <PieChart>\n <Tooltip />\n <Legend />\n <Pie\n data={data}\n dataKey={valueKey}\n nameKey={xKey}\n cx=\"50%\"\n cy=\"50%\"\n outerRadius={110}\n innerRadius={type === \"DONUT\" ? 60 : 0}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n label={(entry: any) => formatValue(entry?.name)}\n >\n {data.map((_, i) => (\n <Cell key={i} fill={color(i)} />\n ))}\n </Pie>\n </PieChart>\n </Frame>\n );\n }\n\n case \"SCATTER\": {\n const xNum = seriesKeys[0];\n const yNum = seriesKeys[1] ?? seriesKeys[0];\n return (\n <Frame>\n <ScatterChart>\n {grid()}\n <XAxis dataKey={xNum ?? xKey} type=\"number\" tick={AXIS_TICK} name={xNum ?? xKey} />\n <YAxis dataKey={yNum} type=\"number\" tick={AXIS_TICK} name={yNum} />\n <ZAxis range={[60, 60]} />\n <Tooltip cursor={{ strokeDasharray: \"3 3\" }} />\n <Scatter data={data} fill={color(0)} />\n </ScatterChart>\n </Frame>\n );\n }\n\n // HEATMAP (and anything Recharts can't express) → a readable data preview.\n default:\n return <PreviewTable block={block} data={data} />;\n }\n}\n\nconst AXIS_TICK = { fontSize: 12 } as const;\nconst grid = () => <CartesianGrid strokeDasharray=\"3 3\" stroke=\"#eee\" />;\n\nfunction Frame({ children }: { children: ReactElement }) {\n return (\n <div className=\"rk-chart\">\n <ResponsiveContainer width=\"100%\" height={HEIGHT}>\n {children}\n </ResponsiveContainer>\n </div>\n );\n}\n\nfunction PreviewTable({\n block,\n data,\n}: {\n block: ChartBlockType;\n data: Record<string, unknown>[];\n}) {\n const keys = Object.keys(data[0] ?? {});\n const preview = data.slice(0, 8);\n return (\n <div className=\"rk-chart-fallback\" data-chart-type={block.chartType}>\n <div className=\"rk-chart-badge\">\n {block.chartType} · rendered as a table (no chart mapping)\n </div>\n <table className=\"rk-table rk-chart-preview\">\n <thead>\n <tr>\n {keys.map((k) => (\n <th key={k} scope=\"col\">\n {k}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {preview.map((row, i) => (\n <tr key={i}>\n {keys.map((k) => (\n <td key={k}>{formatValue(row[k])}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {data.length > preview.length ? (\n <p className=\"rk-chart-more\">+{data.length - preview.length} more rows</p>\n ) : null}\n </div>\n );\n}\n"]}
@@ -0,0 +1,151 @@
1
+ import { formatValue } from './chunk-3FSZRQQU.js';
2
+ import { ScatterChart, XAxis, YAxis, ZAxis, Tooltip, Scatter, PieChart, Legend, Pie, Cell, BarChart, Bar, AreaChart, Area, LineChart, Line, CartesianGrid, ResponsiveContainer } from 'recharts';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ var PALETTE = [
6
+ "#2563eb",
7
+ "#16a34a",
8
+ "#d97706",
9
+ "#dc2626",
10
+ "#7c3aed",
11
+ "#0891b2",
12
+ "#db2777",
13
+ "#65a30d"
14
+ ];
15
+ function inferShape(data) {
16
+ const first = data[0] ?? {};
17
+ const keys = Object.keys(first);
18
+ const isNumericCol = (k) => data.some((row) => typeof row[k] === "number");
19
+ const xKey = keys.find((k) => !isNumericCol(k)) ?? keys[0] ?? "x";
20
+ const seriesKeys = keys.filter((k) => k !== xKey && isNumericCol(k));
21
+ return {
22
+ xKey,
23
+ seriesKeys: seriesKeys.length ? seriesKeys : keys.filter((k) => k !== xKey)
24
+ };
25
+ }
26
+ var HEIGHT = 300;
27
+ var color = (i) => PALETTE[i % PALETTE.length];
28
+ function ChartRenderer({ block }) {
29
+ const data = Array.isArray(block.data) ? block.data : [];
30
+ if (data.length === 0) return /* @__PURE__ */ jsx("p", { className: "rk-empty", children: "No chart data." });
31
+ const { xKey, seriesKeys } = inferShape(data);
32
+ const type = block.chartType;
33
+ switch (type) {
34
+ case "LINE":
35
+ return /* @__PURE__ */ jsx(Frame, { children: /* @__PURE__ */ jsxs(LineChart, { data, children: [
36
+ grid(),
37
+ /* @__PURE__ */ jsx(XAxis, { dataKey: xKey, tick: AXIS_TICK }),
38
+ /* @__PURE__ */ jsx(YAxis, { tick: AXIS_TICK }),
39
+ /* @__PURE__ */ jsx(Tooltip, {}),
40
+ seriesKeys.length > 1 ? /* @__PURE__ */ jsx(Legend, {}) : null,
41
+ seriesKeys.map((k, i) => /* @__PURE__ */ jsx(Line, { type: "monotone", dataKey: k, stroke: color(i), strokeWidth: 2, dot: false }, k))
42
+ ] }) });
43
+ case "AREA":
44
+ case "STACKED_AREA":
45
+ return /* @__PURE__ */ jsx(Frame, { children: /* @__PURE__ */ jsxs(AreaChart, { data, children: [
46
+ grid(),
47
+ /* @__PURE__ */ jsx(XAxis, { dataKey: xKey, tick: AXIS_TICK }),
48
+ /* @__PURE__ */ jsx(YAxis, { tick: AXIS_TICK }),
49
+ /* @__PURE__ */ jsx(Tooltip, {}),
50
+ seriesKeys.length > 1 ? /* @__PURE__ */ jsx(Legend, {}) : null,
51
+ seriesKeys.map((k, i) => /* @__PURE__ */ jsx(
52
+ Area,
53
+ {
54
+ type: "monotone",
55
+ dataKey: k,
56
+ stackId: type === "STACKED_AREA" ? "stack" : void 0,
57
+ stroke: color(i),
58
+ fill: color(i),
59
+ fillOpacity: 0.25
60
+ },
61
+ k
62
+ ))
63
+ ] }) });
64
+ case "BAR":
65
+ case "STACKED_BAR":
66
+ return /* @__PURE__ */ jsx(Frame, { children: /* @__PURE__ */ jsxs(BarChart, { data, children: [
67
+ grid(),
68
+ /* @__PURE__ */ jsx(XAxis, { dataKey: xKey, tick: AXIS_TICK }),
69
+ /* @__PURE__ */ jsx(YAxis, { tick: AXIS_TICK }),
70
+ /* @__PURE__ */ jsx(Tooltip, {}),
71
+ seriesKeys.length > 1 ? /* @__PURE__ */ jsx(Legend, {}) : null,
72
+ seriesKeys.map((k, i) => /* @__PURE__ */ jsx(
73
+ Bar,
74
+ {
75
+ dataKey: k,
76
+ stackId: type === "STACKED_BAR" ? "stack" : void 0,
77
+ fill: color(i)
78
+ },
79
+ k
80
+ ))
81
+ ] }) });
82
+ case "PIE":
83
+ case "DONUT": {
84
+ const valueKey = seriesKeys[0] ?? "value";
85
+ return /* @__PURE__ */ jsx(Frame, { children: /* @__PURE__ */ jsxs(PieChart, { children: [
86
+ /* @__PURE__ */ jsx(Tooltip, {}),
87
+ /* @__PURE__ */ jsx(Legend, {}),
88
+ /* @__PURE__ */ jsx(
89
+ Pie,
90
+ {
91
+ data,
92
+ dataKey: valueKey,
93
+ nameKey: xKey,
94
+ cx: "50%",
95
+ cy: "50%",
96
+ outerRadius: 110,
97
+ innerRadius: type === "DONUT" ? 60 : 0,
98
+ label: (entry) => formatValue(entry?.name),
99
+ children: data.map((_, i) => /* @__PURE__ */ jsx(Cell, { fill: color(i) }, i))
100
+ }
101
+ )
102
+ ] }) });
103
+ }
104
+ case "SCATTER": {
105
+ const xNum = seriesKeys[0];
106
+ const yNum = seriesKeys[1] ?? seriesKeys[0];
107
+ return /* @__PURE__ */ jsx(Frame, { children: /* @__PURE__ */ jsxs(ScatterChart, { children: [
108
+ grid(),
109
+ /* @__PURE__ */ jsx(XAxis, { dataKey: xNum ?? xKey, type: "number", tick: AXIS_TICK, name: xNum ?? xKey }),
110
+ /* @__PURE__ */ jsx(YAxis, { dataKey: yNum, type: "number", tick: AXIS_TICK, name: yNum }),
111
+ /* @__PURE__ */ jsx(ZAxis, { range: [60, 60] }),
112
+ /* @__PURE__ */ jsx(Tooltip, { cursor: { strokeDasharray: "3 3" } }),
113
+ /* @__PURE__ */ jsx(Scatter, { data, fill: color(0) })
114
+ ] }) });
115
+ }
116
+ // HEATMAP (and anything Recharts can't express) → a readable data preview.
117
+ default:
118
+ return /* @__PURE__ */ jsx(PreviewTable, { block, data });
119
+ }
120
+ }
121
+ var AXIS_TICK = { fontSize: 12 };
122
+ var grid = () => /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "#eee" });
123
+ function Frame({ children }) {
124
+ return /* @__PURE__ */ jsx("div", { className: "rk-chart", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: HEIGHT, children }) });
125
+ }
126
+ function PreviewTable({
127
+ block,
128
+ data
129
+ }) {
130
+ const keys = Object.keys(data[0] ?? {});
131
+ const preview = data.slice(0, 8);
132
+ return /* @__PURE__ */ jsxs("div", { className: "rk-chart-fallback", "data-chart-type": block.chartType, children: [
133
+ /* @__PURE__ */ jsxs("div", { className: "rk-chart-badge", children: [
134
+ block.chartType,
135
+ " \xB7 rendered as a table (no chart mapping)"
136
+ ] }),
137
+ /* @__PURE__ */ jsxs("table", { className: "rk-table rk-chart-preview", children: [
138
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: keys.map((k) => /* @__PURE__ */ jsx("th", { scope: "col", children: k }, k)) }) }),
139
+ /* @__PURE__ */ jsx("tbody", { children: preview.map((row, i) => /* @__PURE__ */ jsx("tr", { children: keys.map((k) => /* @__PURE__ */ jsx("td", { children: formatValue(row[k]) }, k)) }, i)) })
140
+ ] }),
141
+ data.length > preview.length ? /* @__PURE__ */ jsxs("p", { className: "rk-chart-more", children: [
142
+ "+",
143
+ data.length - preview.length,
144
+ " more rows"
145
+ ] }) : null
146
+ ] });
147
+ }
148
+
149
+ export { ChartRenderer as default };
150
+ //# sourceMappingURL=ChartRenderer-URPZESVN.js.map
151
+ //# sourceMappingURL=ChartRenderer-URPZESVN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blocks/ChartRenderer.tsx"],"names":[],"mappings":";;;;AAkCA,IAAM,OAAA,GAAU;AAAA,EACd,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAOA,SAAS,WAAW,IAAA,EAA2C;AAC7D,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,CAAC,CAAA,IAAK,EAAC;AAC1B,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAC9B,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAc,IAAA,CAAK,IAAA,CAAK,CAAC,GAAA,KAAQ,OAAO,GAAA,CAAI,CAAC,CAAA,KAAM,QAAQ,CAAA;AACjF,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAC,YAAA,CAAa,CAAC,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA,IAAK,GAAA;AAC9D,EAAA,MAAM,UAAA,GAAa,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,KAAM,IAAA,IAAQ,YAAA,CAAa,CAAC,CAAC,CAAA;AAEnE,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,UAAA,EAAY,WAAW,MAAA,GAAS,UAAA,GAAa,KAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,KAAM,IAAI;AAAA,GAC5E;AACF;AAEA,IAAM,MAAA,GAAS,GAAA;AACf,IAAM,QAAQ,CAAC,CAAA,KAAc,OAAA,CAAQ,CAAA,GAAI,QAAQ,MAAM,CAAA;AAExC,SAAR,aAAA,CAA+B,EAAE,KAAA,EAAM,EAA8B;AAC1E,EAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA,GAAK,KAAA,CAAM,OAAqC,EAAC;AACtF,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG,2BAAQ,GAAA,EAAA,EAAE,SAAA,EAAU,YAAW,QAAA,EAAA,gBAAA,EAAc,CAAA;AAEpE,EAAA,MAAM,EAAE,IAAA,EAAM,UAAA,EAAW,GAAI,WAAW,IAAI,CAAA;AAC5C,EAAA,MAAM,OAAO,KAAA,CAAM,SAAA;AAEnB,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,MAAA;AACH,MAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EACR,QAAA,EAAA;AAAA,QAAA,IAAA,EAAK;AAAA,wBACN,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAS,IAAA,EAAM,MAAM,SAAA,EAAW,CAAA;AAAA,wBACvC,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,SAAA,EAAW,CAAA;AAAA,4BACvB,OAAA,EAAA,EAAQ,CAAA;AAAA,QACR,UAAA,CAAW,MAAA,GAAS,CAAA,mBAAI,GAAA,CAAC,UAAO,CAAA,GAAK,IAAA;AAAA,QACrC,UAAA,CAAW,IAAI,CAAC,CAAA,EAAG,sBAClB,GAAA,CAAC,IAAA,EAAA,EAAa,MAAK,UAAA,EAAW,OAAA,EAAS,GAAG,MAAA,EAAQ,KAAA,CAAM,CAAC,CAAA,EAAG,WAAA,EAAa,GAAG,GAAA,EAAK,KAAA,EAAA,EAAtE,CAA6E,CACzF;AAAA,OAAA,EACH,CAAA,EACF,CAAA;AAAA,IAGJ,KAAK,MAAA;AAAA,IACL,KAAK,cAAA;AACH,MAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EACR,QAAA,EAAA;AAAA,QAAA,IAAA,EAAK;AAAA,wBACN,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAS,IAAA,EAAM,MAAM,SAAA,EAAW,CAAA;AAAA,wBACvC,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,SAAA,EAAW,CAAA;AAAA,4BACvB,OAAA,EAAA,EAAQ,CAAA;AAAA,QACR,UAAA,CAAW,MAAA,GAAS,CAAA,mBAAI,GAAA,CAAC,UAAO,CAAA,GAAK,IAAA;AAAA,QACrC,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBAClB,GAAA;AAAA,UAAC,IAAA;AAAA,UAAA;AAAA,YAEC,IAAA,EAAK,UAAA;AAAA,YACL,OAAA,EAAS,CAAA;AAAA,YACT,OAAA,EAAS,IAAA,KAAS,cAAA,GAAiB,OAAA,GAAU,MAAA;AAAA,YAC7C,MAAA,EAAQ,MAAM,CAAC,CAAA;AAAA,YACf,IAAA,EAAM,MAAM,CAAC,CAAA;AAAA,YACb,WAAA,EAAa;AAAA,WAAA;AAAA,UANR;AAAA,SAQR;AAAA,OAAA,EACH,CAAA,EACF,CAAA;AAAA,IAGJ,KAAK,KAAA;AAAA,IACL,KAAK,aAAA;AACH,MAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EACP,QAAA,EAAA;AAAA,QAAA,IAAA,EAAK;AAAA,wBACN,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAS,IAAA,EAAM,MAAM,SAAA,EAAW,CAAA;AAAA,wBACvC,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,SAAA,EAAW,CAAA;AAAA,4BACvB,OAAA,EAAA,EAAQ,CAAA;AAAA,QACR,UAAA,CAAW,MAAA,GAAS,CAAA,mBAAI,GAAA,CAAC,UAAO,CAAA,GAAK,IAAA;AAAA,QACrC,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBAClB,GAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YAEC,OAAA,EAAS,CAAA;AAAA,YACT,OAAA,EAAS,IAAA,KAAS,aAAA,GAAgB,OAAA,GAAU,MAAA;AAAA,YAC5C,IAAA,EAAM,MAAM,CAAC;AAAA,WAAA;AAAA,UAHR;AAAA,SAKR;AAAA,OAAA,EACH,CAAA,EACF,CAAA;AAAA,IAGJ,KAAK,KAAA;AAAA,IACL,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,QAAA,GAAW,UAAA,CAAW,CAAC,CAAA,IAAK,OAAA;AAClC,MAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,QAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,CAAA;AAAA,4BACR,MAAA,EAAA,EAAO,CAAA;AAAA,wBACR,GAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,IAAA;AAAA,YACA,OAAA,EAAS,QAAA;AAAA,YACT,OAAA,EAAS,IAAA;AAAA,YACT,EAAA,EAAG,KAAA;AAAA,YACH,EAAA,EAAG,KAAA;AAAA,YACH,WAAA,EAAa,GAAA;AAAA,YACb,WAAA,EAAa,IAAA,KAAS,OAAA,GAAU,EAAA,GAAK,CAAA;AAAA,YAErC,KAAA,EAAO,CAAC,KAAA,KAAe,WAAA,CAAY,OAAO,IAAI,CAAA;AAAA,YAE7C,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBACZ,GAAA,CAAC,IAAA,EAAA,EAAa,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA,EAAA,EAAhB,CAAmB,CAC/B;AAAA;AAAA;AACH,OAAA,EACF,CAAA,EACF,CAAA;AAAA,IAEJ;AAAA,IAEA,KAAK,SAAA,EAAW;AACd,MAAA,MAAM,IAAA,GAAO,WAAW,CAAC,CAAA;AACzB,MAAA,MAAM,IAAA,GAAO,UAAA,CAAW,CAAC,CAAA,IAAK,WAAW,CAAC,CAAA;AAC1C,MAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,YAAA,EAAA,EACE,QAAA,EAAA;AAAA,QAAA,IAAA,EAAK;AAAA,wBACN,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAS,IAAA,IAAQ,IAAA,EAAM,IAAA,EAAK,QAAA,EAAS,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,IAAA,IAAQ,IAAA,EAAM,CAAA;AAAA,wBACjF,GAAA,CAAC,SAAM,OAAA,EAAS,IAAA,EAAM,MAAK,QAAA,EAAS,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,4BAChE,KAAA,EAAA,EAAM,KAAA,EAAO,CAAC,EAAA,EAAI,EAAE,CAAA,EAAG,CAAA;AAAA,4BACvB,OAAA,EAAA,EAAQ,MAAA,EAAQ,EAAE,eAAA,EAAiB,OAAM,EAAG,CAAA;AAAA,4BAC5C,OAAA,EAAA,EAAQ,IAAA,EAAY,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA,EAAG;AAAA,OAAA,EACvC,CAAA,EACF,CAAA;AAAA,IAEJ;AAAA;AAAA,IAGA;AACE,MAAA,uBAAO,GAAA,CAAC,YAAA,EAAA,EAAa,KAAA,EAAc,IAAA,EAAY,CAAA;AAAA;AAErD;AAEA,IAAM,SAAA,GAAY,EAAE,QAAA,EAAU,EAAA,EAAG;AACjC,IAAM,OAAO,sBAAM,GAAA,CAAC,iBAAc,eAAA,EAAgB,KAAA,EAAM,QAAO,MAAA,EAAO,CAAA;AAEtE,SAAS,KAAA,CAAM,EAAE,QAAA,EAAS,EAA+B;AACvD,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EACb,QAAA,kBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,KAAA,EAAM,MAAA,EAAO,MAAA,EAAQ,MAAA,EACvC,QAAA,EACH,CAAA,EACF,CAAA;AAEJ;AAEA,SAAS,YAAA,CAAa;AAAA,EACpB,KAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,MAAM,OAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA,IAAK,EAAE,CAAA;AACtC,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AAC/B,EAAA,4BACG,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EAAoB,iBAAA,EAAiB,MAAM,SAAA,EACxD,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gBAAA,EACZ,QAAA,EAAA;AAAA,MAAA,KAAA,CAAM,SAAA;AAAA,MAAU;AAAA,KAAA,EACnB,CAAA;AAAA,oBACA,IAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,2BAAA,EACf,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EACE,QAAA,EAAA,IAAA,CAAK,IAAI,CAAC,CAAA,qBACT,GAAA,CAAC,IAAA,EAAA,EAAW,OAAM,KAAA,EACf,QAAA,EAAA,CAAA,EAAA,EADM,CAET,CACD,GACH,CAAA,EACF,CAAA;AAAA,sBACA,GAAA,CAAC,OAAA,EAAA,EACE,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,KAAK,CAAA,qBACjB,GAAA,CAAC,IAAA,EAAA,EACE,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,sBACT,GAAA,CAAC,IAAA,EAAA,EAAY,QAAA,EAAA,WAAA,CAAY,GAAA,CAAI,CAAC,CAAC,CAAA,EAAA,EAAtB,CAAwB,CAClC,CAAA,EAAA,EAHM,CAIT,CACD,CAAA,EACH;AAAA,KAAA,EACF,CAAA;AAAA,IACC,KAAK,MAAA,GAAS,OAAA,CAAQ,yBACrB,IAAA,CAAC,GAAA,EAAA,EAAE,WAAU,eAAA,EAAgB,QAAA,EAAA;AAAA,MAAA,GAAA;AAAA,MAAE,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AAAA,MAAO;AAAA,KAAA,EAAU,CAAA,GACpE;AAAA,GAAA,EACN,CAAA;AAEJ","file":"ChartRenderer-URPZESVN.js","sourcesContent":["import type { ReactElement } from \"react\";\nimport {\n ResponsiveContainer,\n LineChart,\n Line,\n BarChart,\n Bar,\n AreaChart,\n Area,\n PieChart,\n Pie,\n Cell,\n ScatterChart,\n Scatter,\n XAxis,\n YAxis,\n ZAxis,\n CartesianGrid,\n Tooltip,\n Legend,\n} from \"recharts\";\nimport type { ChartBlock as ChartBlockType } from \"@responsekit/schema\";\nimport { formatValue } from \"./util.js\";\n\n/**\n * Real chart adapter, loaded lazily (see `ChartBlock`) so Recharts lands in its own\n * chunk and never weighs down the main bundle. This is the single place the SDK is\n * coupled to a charting library — swap it for visx/nivo/etc. without touching anything\n * else.\n *\n * The backend sends generic rows (e.g. `{ status: \"ONGOING\", count: 10 }`), so we infer\n * the category/x key (first non-numeric column) and the numeric series from the data.\n */\n\nconst PALETTE = [\n \"#2563eb\",\n \"#16a34a\",\n \"#d97706\",\n \"#dc2626\",\n \"#7c3aed\",\n \"#0891b2\",\n \"#db2777\",\n \"#65a30d\",\n];\n\ninterface Inferred {\n xKey: string;\n seriesKeys: string[];\n}\n\nfunction inferShape(data: Record<string, unknown>[]): Inferred {\n const first = data[0] ?? {};\n const keys = Object.keys(first);\n const isNumericCol = (k: string) => data.some((row) => typeof row[k] === \"number\");\n const xKey = keys.find((k) => !isNumericCol(k)) ?? keys[0] ?? \"x\";\n const seriesKeys = keys.filter((k) => k !== xKey && isNumericCol(k));\n // Fallback: if nothing looked numeric, treat every non-x column as a series.\n return {\n xKey,\n seriesKeys: seriesKeys.length ? seriesKeys : keys.filter((k) => k !== xKey),\n };\n}\n\nconst HEIGHT = 300;\nconst color = (i: number) => PALETTE[i % PALETTE.length];\n\nexport default function ChartRenderer({ block }: { block: ChartBlockType }) {\n const data = Array.isArray(block.data) ? (block.data as Record<string, unknown>[]) : [];\n if (data.length === 0) return <p className=\"rk-empty\">No chart data.</p>;\n\n const { xKey, seriesKeys } = inferShape(data);\n const type = block.chartType;\n\n switch (type) {\n case \"LINE\":\n return (\n <Frame>\n <LineChart data={data}>\n {grid()}\n <XAxis dataKey={xKey} tick={AXIS_TICK} />\n <YAxis tick={AXIS_TICK} />\n <Tooltip />\n {seriesKeys.length > 1 ? <Legend /> : null}\n {seriesKeys.map((k, i) => (\n <Line key={k} type=\"monotone\" dataKey={k} stroke={color(i)} strokeWidth={2} dot={false} />\n ))}\n </LineChart>\n </Frame>\n );\n\n case \"AREA\":\n case \"STACKED_AREA\":\n return (\n <Frame>\n <AreaChart data={data}>\n {grid()}\n <XAxis dataKey={xKey} tick={AXIS_TICK} />\n <YAxis tick={AXIS_TICK} />\n <Tooltip />\n {seriesKeys.length > 1 ? <Legend /> : null}\n {seriesKeys.map((k, i) => (\n <Area\n key={k}\n type=\"monotone\"\n dataKey={k}\n stackId={type === \"STACKED_AREA\" ? \"stack\" : undefined}\n stroke={color(i)}\n fill={color(i)}\n fillOpacity={0.25}\n />\n ))}\n </AreaChart>\n </Frame>\n );\n\n case \"BAR\":\n case \"STACKED_BAR\":\n return (\n <Frame>\n <BarChart data={data}>\n {grid()}\n <XAxis dataKey={xKey} tick={AXIS_TICK} />\n <YAxis tick={AXIS_TICK} />\n <Tooltip />\n {seriesKeys.length > 1 ? <Legend /> : null}\n {seriesKeys.map((k, i) => (\n <Bar\n key={k}\n dataKey={k}\n stackId={type === \"STACKED_BAR\" ? \"stack\" : undefined}\n fill={color(i)}\n />\n ))}\n </BarChart>\n </Frame>\n );\n\n case \"PIE\":\n case \"DONUT\": {\n const valueKey = seriesKeys[0] ?? \"value\";\n return (\n <Frame>\n <PieChart>\n <Tooltip />\n <Legend />\n <Pie\n data={data}\n dataKey={valueKey}\n nameKey={xKey}\n cx=\"50%\"\n cy=\"50%\"\n outerRadius={110}\n innerRadius={type === \"DONUT\" ? 60 : 0}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n label={(entry: any) => formatValue(entry?.name)}\n >\n {data.map((_, i) => (\n <Cell key={i} fill={color(i)} />\n ))}\n </Pie>\n </PieChart>\n </Frame>\n );\n }\n\n case \"SCATTER\": {\n const xNum = seriesKeys[0];\n const yNum = seriesKeys[1] ?? seriesKeys[0];\n return (\n <Frame>\n <ScatterChart>\n {grid()}\n <XAxis dataKey={xNum ?? xKey} type=\"number\" tick={AXIS_TICK} name={xNum ?? xKey} />\n <YAxis dataKey={yNum} type=\"number\" tick={AXIS_TICK} name={yNum} />\n <ZAxis range={[60, 60]} />\n <Tooltip cursor={{ strokeDasharray: \"3 3\" }} />\n <Scatter data={data} fill={color(0)} />\n </ScatterChart>\n </Frame>\n );\n }\n\n // HEATMAP (and anything Recharts can't express) → a readable data preview.\n default:\n return <PreviewTable block={block} data={data} />;\n }\n}\n\nconst AXIS_TICK = { fontSize: 12 } as const;\nconst grid = () => <CartesianGrid strokeDasharray=\"3 3\" stroke=\"#eee\" />;\n\nfunction Frame({ children }: { children: ReactElement }) {\n return (\n <div className=\"rk-chart\">\n <ResponsiveContainer width=\"100%\" height={HEIGHT}>\n {children}\n </ResponsiveContainer>\n </div>\n );\n}\n\nfunction PreviewTable({\n block,\n data,\n}: {\n block: ChartBlockType;\n data: Record<string, unknown>[];\n}) {\n const keys = Object.keys(data[0] ?? {});\n const preview = data.slice(0, 8);\n return (\n <div className=\"rk-chart-fallback\" data-chart-type={block.chartType}>\n <div className=\"rk-chart-badge\">\n {block.chartType} · rendered as a table (no chart mapping)\n </div>\n <table className=\"rk-table rk-chart-preview\">\n <thead>\n <tr>\n {keys.map((k) => (\n <th key={k} scope=\"col\">\n {k}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {preview.map((row, i) => (\n <tr key={i}>\n {keys.map((k) => (\n <td key={k}>{formatValue(row[k])}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {data.length > preview.length ? (\n <p className=\"rk-chart-more\">+{data.length - preview.length} more rows</p>\n ) : null}\n </div>\n );\n}\n"]}
@@ -0,0 +1,33 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/blocks/util.ts
8
+ function formatValue(value) {
9
+ if (value === null || value === void 0) return "";
10
+ if (typeof value === "string") return value;
11
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
12
+ try {
13
+ return JSON.stringify(value);
14
+ } catch {
15
+ return String(value);
16
+ }
17
+ }
18
+ function isDev() {
19
+ const g = globalThis;
20
+ const env = g.process?.env?.NODE_ENV;
21
+ return env !== void 0 && env !== "production";
22
+ }
23
+ function rowsToCsv(columns, rows) {
24
+ const escape = (s) => `"${s.replace(/"/g, '""')}"`;
25
+ const header = columns.map((c) => escape(c.label)).join(",");
26
+ const body = rows.map((row) => columns.map((c) => escape(formatValue(row[c.key]))).join(",")).join("\n");
27
+ return `${header}
28
+ ${body}`;
29
+ }
30
+
31
+ export { __export, formatValue, isDev, rowsToCsv };
32
+ //# sourceMappingURL=chunk-3FSZRQQU.js.map
33
+ //# sourceMappingURL=chunk-3FSZRQQU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blocks/util.ts"],"names":[],"mappings":";;;;;;;AAMO,SAAS,YAAY,KAAA,EAAwB;AAClD,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAO,EAAA;AAClD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,SAAA,EAAW,OAAO,OAAO,KAAK,CAAA;AAChF,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AACF;AAGO,SAAS,KAAA,GAAiB;AAG/B,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,OAAA,EAAS,GAAA,EAAK,QAAA;AAC5B,EAAA,OAAO,GAAA,KAAQ,UAAa,GAAA,KAAQ,YAAA;AACtC;AAGO,SAAS,SAAA,CACd,SACA,IAAA,EACQ;AACR,EAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAc,CAAA,CAAA,EAAI,EAAE,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAC,CAAA,CAAA,CAAA;AACvD,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,CAAA,CAAE,KAAK,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAC3D,EAAA,MAAM,IAAA,GAAO,KACV,GAAA,CAAI,CAAC,QAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,WAAA,CAAY,IAAI,CAAA,CAAE,GAAG,CAAC,CAAC,CAAC,CAAA,CAAE,KAAK,GAAG,CAAC,CAAA,CAC1E,IAAA,CAAK,IAAI,CAAA;AACZ,EAAA,OAAO,GAAG,MAAM;AAAA,EAAK,IAAI,CAAA,CAAA;AAC3B","file":"chunk-3FSZRQQU.js","sourcesContent":["/**\n * Value helpers for rendering untrusted data. Everything here returns a plain string\n * that React escapes on render — no HTML is ever produced.\n */\n\n/** Render an arbitrary cell/KPI value as display text. Never throws. */\nexport function formatValue(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/** True when running in a dev build (used to optionally surface raw JSON in fallbacks). */\nexport function isDev(): boolean {\n // Read NODE_ENV off globalThis so we don't depend on Node's `process` typings in a\n // browser-targeted package. Bundlers (Vite/webpack/esbuild) inline this at build time.\n const g = globalThis as { process?: { env?: Record<string, string | undefined> } };\n const env = g.process?.env?.NODE_ENV;\n return env !== undefined && env !== \"production\";\n}\n\n/** Convert table rows to CSV for a DOWNLOAD action. Pure data, no HTML. */\nexport function rowsToCsv(\n columns: { key: string; label: string }[],\n rows: Record<string, unknown>[],\n): string {\n const escape = (s: string) => `\"${s.replace(/\"/g, '\"\"')}\"`;\n const header = columns.map((c) => escape(c.label)).join(\",\");\n const body = rows\n .map((row) => columns.map((c) => escape(formatValue(row[c.key]))).join(\",\"))\n .join(\"\\n\");\n return `${header}\\n${body}`;\n}\n"]}
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __export = (target, all) => {
5
+ for (var name in all)
6
+ __defProp(target, name, { get: all[name], enumerable: true });
7
+ };
8
+
9
+ // src/blocks/util.ts
10
+ function formatValue(value) {
11
+ if (value === null || value === void 0) return "";
12
+ if (typeof value === "string") return value;
13
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
14
+ try {
15
+ return JSON.stringify(value);
16
+ } catch {
17
+ return String(value);
18
+ }
19
+ }
20
+ function isDev() {
21
+ const g = globalThis;
22
+ const env = g.process?.env?.NODE_ENV;
23
+ return env !== void 0 && env !== "production";
24
+ }
25
+ function rowsToCsv(columns, rows) {
26
+ const escape = (s) => `"${s.replace(/"/g, '""')}"`;
27
+ const header = columns.map((c) => escape(c.label)).join(",");
28
+ const body = rows.map((row) => columns.map((c) => escape(formatValue(row[c.key]))).join(",")).join("\n");
29
+ return `${header}
30
+ ${body}`;
31
+ }
32
+
33
+ exports.__export = __export;
34
+ exports.formatValue = formatValue;
35
+ exports.isDev = isDev;
36
+ exports.rowsToCsv = rowsToCsv;
37
+ //# sourceMappingURL=chunk-D4WIPDH3.cjs.map
38
+ //# sourceMappingURL=chunk-D4WIPDH3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blocks/util.ts"],"names":[],"mappings":";;;;;;;;;AAMO,SAAS,YAAY,KAAA,EAAwB;AAClD,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAO,EAAA;AAClD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,SAAA,EAAW,OAAO,OAAO,KAAK,CAAA;AAChF,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AACF;AAGO,SAAS,KAAA,GAAiB;AAG/B,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,OAAA,EAAS,GAAA,EAAK,QAAA;AAC5B,EAAA,OAAO,GAAA,KAAQ,UAAa,GAAA,KAAQ,YAAA;AACtC;AAGO,SAAS,SAAA,CACd,SACA,IAAA,EACQ;AACR,EAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAc,CAAA,CAAA,EAAI,EAAE,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAC,CAAA,CAAA,CAAA;AACvD,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,CAAA,CAAE,KAAK,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAC3D,EAAA,MAAM,IAAA,GAAO,KACV,GAAA,CAAI,CAAC,QAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,WAAA,CAAY,IAAI,CAAA,CAAE,GAAG,CAAC,CAAC,CAAC,CAAA,CAAE,KAAK,GAAG,CAAC,CAAA,CAC1E,IAAA,CAAK,IAAI,CAAA;AACZ,EAAA,OAAO,GAAG,MAAM;AAAA,EAAK,IAAI,CAAA,CAAA;AAC3B","file":"chunk-D4WIPDH3.cjs","sourcesContent":["/**\n * Value helpers for rendering untrusted data. Everything here returns a plain string\n * that React escapes on render — no HTML is ever produced.\n */\n\n/** Render an arbitrary cell/KPI value as display text. Never throws. */\nexport function formatValue(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/** True when running in a dev build (used to optionally surface raw JSON in fallbacks). */\nexport function isDev(): boolean {\n // Read NODE_ENV off globalThis so we don't depend on Node's `process` typings in a\n // browser-targeted package. Bundlers (Vite/webpack/esbuild) inline this at build time.\n const g = globalThis as { process?: { env?: Record<string, string | undefined> } };\n const env = g.process?.env?.NODE_ENV;\n return env !== undefined && env !== \"production\";\n}\n\n/** Convert table rows to CSV for a DOWNLOAD action. Pure data, no HTML. */\nexport function rowsToCsv(\n columns: { key: string; label: string }[],\n rows: Record<string, unknown>[],\n): string {\n const escape = (s: string) => `\"${s.replace(/\"/g, '\"\"')}\"`;\n const header = columns.map((c) => escape(c.label)).join(\",\");\n const body = rows\n .map((row) => columns.map((c) => escape(formatValue(row[c.key]))).join(\",\"))\n .join(\"\\n\");\n return `${header}\\n${body}`;\n}\n"]}