@assistant-ui/react-generative-ui 0.0.21 → 0.0.22
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/LICENSE +1 -1
- package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.client.js +30 -13
- package/dist/JSONGenerativeUI.client.js.map +1 -1
- package/dist/RadioGroupScope.d.ts +6 -0
- package/dist/RadioGroupScope.d.ts.map +1 -0
- package/dist/RadioGroupScope.js +25 -0
- package/dist/RadioGroupScope.js.map +1 -0
- package/dist/a2ui/BindingContext.d.ts +11 -0
- package/dist/a2ui/BindingContext.d.ts.map +1 -0
- package/dist/a2ui/BindingContext.js +12 -0
- package/dist/a2ui/BindingContext.js.map +1 -0
- package/dist/a2ui/PresentRenderer.d.ts +11 -0
- package/dist/a2ui/PresentRenderer.d.ts.map +1 -0
- package/dist/a2ui/PresentRenderer.js +39 -0
- package/dist/a2ui/PresentRenderer.js.map +1 -0
- package/dist/a2ui/convert.d.ts +6 -0
- package/dist/a2ui/convert.d.ts.map +1 -1
- package/dist/a2ui/convert.js +344 -83
- package/dist/a2ui/convert.js.map +1 -1
- package/dist/a2ui/dataModel.d.ts +9 -0
- package/dist/a2ui/dataModel.d.ts.map +1 -0
- package/dist/a2ui/dataModel.js +44 -0
- package/dist/a2ui/dataModel.js.map +1 -0
- package/dist/a2ui/reducer.d.ts +5 -0
- package/dist/a2ui/reducer.d.ts.map +1 -1
- package/dist/a2ui/reducer.js +3 -3
- package/dist/a2ui/reducer.js.map +1 -1
- package/dist/a2ui/types.d.ts +8 -2
- package/dist/a2ui/types.d.ts.map +1 -1
- package/dist/a2ui/types.js.map +1 -1
- package/dist/a2ui/valueFunctions.d.ts +16 -0
- package/dist/a2ui/valueFunctions.d.ts.map +1 -0
- package/dist/a2ui/valueFunctions.js +332 -0
- package/dist/a2ui/valueFunctions.js.map +1 -0
- package/dist/actionRegistry.d.ts +1 -1
- package/dist/actionRegistry.js.map +1 -1
- package/dist/answeredValues.d.ts +16 -0
- package/dist/answeredValues.d.ts.map +1 -0
- package/dist/answeredValues.js +37 -0
- package/dist/answeredValues.js.map +1 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/fieldReferences.d.ts +9 -0
- package/dist/fieldReferences.d.ts.map +1 -0
- package/dist/fieldReferences.js +53 -0
- package/dist/fieldReferences.js.map +1 -0
- package/dist/generativeUIToJSX.js +3 -3
- package/dist/generativeUIToJSX.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.server.js +2 -2
- package/dist/index.shared.js +2 -2
- package/dist/ir.d.ts +1 -1
- package/dist/ir.js.map +1 -1
- package/dist/renderGenerativeUI.d.ts.map +1 -1
- package/dist/renderGenerativeUI.js +12 -1
- package/dist/renderGenerativeUI.js.map +1 -1
- package/dist/slack/constants.d.ts +2 -0
- package/dist/slack/constants.d.ts.map +1 -1
- package/dist/slack/constants.js +3 -1
- package/dist/slack/constants.js.map +1 -1
- package/dist/slack/decodeBlockAction.d.ts +3 -1
- package/dist/slack/decodeBlockAction.d.ts.map +1 -1
- package/dist/slack/decodeBlockAction.js +58 -7
- package/dist/slack/decodeBlockAction.js.map +1 -1
- package/dist/slack/fromSlackBlocks.d.ts.map +1 -1
- package/dist/slack/fromSlackBlocks.js +20 -3
- package/dist/slack/fromSlackBlocks.js.map +1 -1
- package/dist/slack/toSlackBlocks.d.ts.map +1 -1
- package/dist/slack/toSlackBlocks.js +187 -19
- package/dist/slack/toSlackBlocks.js.map +1 -1
- package/dist/slack/types.d.ts +4 -0
- package/dist/slack/types.d.ts.map +1 -1
- package/dist/teams/constants.d.ts +1 -1
- package/dist/teams/constants.d.ts.map +1 -1
- package/dist/teams/constants.js +1 -1
- package/dist/teams/constants.js.map +1 -1
- package/dist/teams/decodeSubmitData.d.ts +4 -0
- package/dist/teams/decodeSubmitData.d.ts.map +1 -1
- package/dist/teams/decodeSubmitData.js +6 -1
- package/dist/teams/decodeSubmitData.js.map +1 -1
- package/dist/teams/toAdaptiveCard.d.ts +5 -4
- package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
- package/dist/teams/toAdaptiveCard.js +56 -17
- package/dist/teams/toAdaptiveCard.js.map +1 -1
- package/dist/teams/types.d.ts +4 -1
- package/dist/teams/types.d.ts.map +1 -1
- package/dist/vocabulary/alert.d.ts +9 -2
- package/dist/vocabulary/alert.d.ts.map +1 -1
- package/dist/vocabulary/alert.js +116 -19
- package/dist/vocabulary/alert.js.map +1 -1
- package/dist/vocabulary/collectFormValues.d.ts +2 -1
- package/dist/vocabulary/collectFormValues.d.ts.map +1 -1
- package/dist/vocabulary/collectFormValues.js +10 -3
- package/dist/vocabulary/collectFormValues.js.map +1 -1
- package/dist/vocabulary/data.d.ts +22 -5
- package/dist/vocabulary/data.d.ts.map +1 -1
- package/dist/vocabulary/data.js +278 -83
- package/dist/vocabulary/data.js.map +1 -1
- package/dist/vocabulary/dispatch.d.ts +3 -2
- package/dist/vocabulary/dispatch.d.ts.map +1 -1
- package/dist/vocabulary/dispatch.js +33 -4
- package/dist/vocabulary/dispatch.js.map +1 -1
- package/dist/vocabulary/fact.d.ts +8 -1
- package/dist/vocabulary/fact.d.ts.map +1 -1
- package/dist/vocabulary/fact.js +37 -11
- package/dist/vocabulary/fact.js.map +1 -1
- package/dist/vocabulary/form.d.ts.map +1 -1
- package/dist/vocabulary/form.js +3 -3
- package/dist/vocabulary/form.js.map +1 -1
- package/dist/vocabulary/formatValue.d.ts +7 -0
- package/dist/vocabulary/formatValue.d.ts.map +1 -0
- package/dist/vocabulary/formatValue.js +76 -0
- package/dist/vocabulary/formatValue.js.map +1 -0
- package/dist/vocabulary/icon.d.ts +1 -1
- package/dist/vocabulary/interactive.d.ts +137 -8
- package/dist/vocabulary/interactive.d.ts.map +1 -1
- package/dist/vocabulary/interactive.js +404 -103
- package/dist/vocabulary/interactive.js.map +1 -1
- package/dist/vocabulary/layout.d.ts.map +1 -1
- package/dist/vocabulary/layout.js +4 -4
- package/dist/vocabulary/layout.js.map +1 -1
- package/dist/vocabulary/list.js +2 -2
- package/dist/vocabulary/list.js.map +1 -1
- package/dist/vocabulary/text.d.ts +1 -1
- package/package.json +6 -3
- package/src/JSONGenerativeUI.client.tsx +84 -40
- package/src/JSONGenerativeUI.test.tsx +964 -68
- package/src/RadioGroupScope.server.test.tsx +24 -0
- package/src/RadioGroupScope.tsx +34 -0
- package/src/a2ui/BindingContext.ts +26 -0
- package/src/a2ui/PresentRenderer.tsx +83 -0
- package/src/a2ui/convert.test.ts +1795 -179
- package/src/a2ui/convert.ts +629 -132
- package/src/a2ui/dataModel.ts +69 -0
- package/src/a2ui/reducer.test.ts +35 -0
- package/src/a2ui/reducer.ts +5 -4
- package/src/a2ui/types.ts +9 -2
- package/src/a2ui/valueFunctions.test.ts +271 -0
- package/src/a2ui/valueFunctions.ts +523 -0
- package/src/actionRegistry.ts +1 -1
- package/src/answeredValues.test.ts +33 -0
- package/src/answeredValues.tsx +70 -0
- package/src/constants.ts +4 -0
- package/src/fieldReferences.test.ts +66 -0
- package/src/fieldReferences.ts +83 -0
- package/src/generativeUIToJSX.test.ts +18 -0
- package/src/generativeUIToJSX.ts +4 -6
- package/src/index.server.test.ts +106 -0
- package/src/ir.ts +1 -1
- package/src/renderGenerativeUI.test.tsx +14 -5
- package/src/renderGenerativeUI.tsx +30 -1
- package/src/slack/a2uiSlack.test.ts +198 -0
- package/src/slack/constants.ts +3 -0
- package/src/slack/decodeBlockAction.test.ts +98 -0
- package/src/slack/decodeBlockAction.ts +110 -17
- package/src/slack/fromSlackBlocks.test.ts +222 -3
- package/src/slack/fromSlackBlocks.ts +53 -2
- package/src/slack/toSlackBlocks.test.ts +682 -3
- package/src/slack/toSlackBlocks.ts +374 -23
- package/src/slack/types.ts +4 -0
- package/src/teams/constants.ts +1 -1
- package/src/teams/decodeSubmitData.test.ts +33 -0
- package/src/teams/decodeSubmitData.ts +9 -1
- package/src/teams/toAdaptiveCard.test.ts +219 -0
- package/src/teams/toAdaptiveCard.ts +93 -19
- package/src/teams/types.ts +4 -1
- package/src/vocabulary/alert.test.tsx +288 -7
- package/src/vocabulary/alert.tsx +168 -26
- package/src/vocabulary/collectFormValues.test.ts +28 -1
- package/src/vocabulary/collectFormValues.ts +25 -5
- package/src/vocabulary/data.test.tsx +248 -6
- package/src/vocabulary/data.tsx +398 -100
- package/src/vocabulary/dispatch.ts +63 -2
- package/src/vocabulary/fact.test.tsx +67 -0
- package/src/vocabulary/fact.tsx +40 -9
- package/src/vocabulary/form.tsx +7 -2
- package/src/vocabulary/formatValue.test.ts +72 -0
- package/src/vocabulary/formatValue.ts +127 -0
- package/src/vocabulary/index.test.ts +2 -0
- package/src/vocabulary/interactive.dispatch.test.tsx +167 -79
- package/src/vocabulary/interactive.dom.test.tsx +1699 -0
- package/src/vocabulary/interactive.test.tsx +60 -4
- package/src/vocabulary/interactive.tsx +770 -151
- package/src/vocabulary/layout.test.tsx +6 -4
- package/src/vocabulary/layout.tsx +13 -2
- package/src/vocabulary/list.tsx +2 -2
package/dist/vocabulary/data.js
CHANGED
|
@@ -1,25 +1,111 @@
|
|
|
1
1
|
import { toTextContent } from "./toTextContent.js";
|
|
2
|
-
import {
|
|
2
|
+
import { formatValue, isNumericTableFormat } from "./formatValue.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
3
5
|
import { z } from "zod";
|
|
4
6
|
//#region src/vocabulary/data.tsx
|
|
5
|
-
const columnSchema = z.object({
|
|
7
|
+
const columnSchema = z.object({
|
|
8
|
+
label: z.string().describe("Column header label."),
|
|
9
|
+
align: z.enum(["start", "end"]).optional().describe("Cell alignment."),
|
|
10
|
+
format: z.object({
|
|
11
|
+
kind: z.enum([
|
|
12
|
+
"number",
|
|
13
|
+
"currency",
|
|
14
|
+
"percent",
|
|
15
|
+
"date"
|
|
16
|
+
]).describe("Format kind. `percent` takes a fraction, so 0.25 renders as 25%."),
|
|
17
|
+
currency: z.string().optional().describe("Currency code."),
|
|
18
|
+
decimals: z.number().optional().describe("Decimal places.")
|
|
19
|
+
}).optional().describe("Cell value format.")
|
|
20
|
+
});
|
|
6
21
|
const cellSchema = z.union([
|
|
7
22
|
z.string(),
|
|
8
23
|
z.number(),
|
|
9
24
|
z.boolean()
|
|
10
25
|
]).describe("A cell value.");
|
|
26
|
+
const tableCollator = new Intl.Collator("en-US", { numeric: true });
|
|
11
27
|
const isTableColumn = (column) => column !== null && typeof column === "object" && "label" in column && typeof column.label === "string";
|
|
12
28
|
const isTableCell = (cell) => typeof cell === "string" || typeof cell === "number" || typeof cell === "boolean";
|
|
29
|
+
const tableAlignment = (column) => {
|
|
30
|
+
if (!isTableColumn(column)) return void 0;
|
|
31
|
+
if (column.align === "start" || column.align === "end") return column.align;
|
|
32
|
+
return isNumericTableFormat(column.format) ? "end" : void 0;
|
|
33
|
+
};
|
|
34
|
+
const compareTableCells = (left, right) => {
|
|
35
|
+
if (typeof left === "number" && Number.isFinite(left) && typeof right === "number" && Number.isFinite(right)) return left - right;
|
|
36
|
+
if (typeof left === "number" && Number.isFinite(left)) return -1;
|
|
37
|
+
if (typeof right === "number" && Number.isFinite(right)) return 1;
|
|
38
|
+
return tableCollator.compare(isTableCell(left) ? String(left) : "", isTableCell(right) ? String(right) : "");
|
|
39
|
+
};
|
|
40
|
+
function TableView({ columns, rows, children, sort, onSort }) {
|
|
41
|
+
const safeColumns = Array.isArray(columns) ? columns : [];
|
|
42
|
+
const hasColumns = safeColumns.some(isTableColumn);
|
|
43
|
+
const safeRows = Array.isArray(rows) ? rows.filter(Array.isArray) : [];
|
|
44
|
+
const sortedRows = sort === void 0 ? safeRows : safeRows.map((row, index) => ({
|
|
45
|
+
row,
|
|
46
|
+
index
|
|
47
|
+
})).sort((left, right) => {
|
|
48
|
+
const comparison = compareTableCells(left.row[sort.column], right.row[sort.column]);
|
|
49
|
+
return comparison === 0 ? left.index - right.index : sort.direction === "ascending" ? comparison : -comparison;
|
|
50
|
+
}).map(({ row }) => row);
|
|
51
|
+
return /* @__PURE__ */ jsxs("table", {
|
|
52
|
+
"data-aui": "table",
|
|
53
|
+
children: [
|
|
54
|
+
hasColumns ? /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: safeColumns.map((column, i) => {
|
|
55
|
+
const label = isTableColumn(column) ? column.label : "";
|
|
56
|
+
const direction = sort?.column === i ? sort.direction : void 0;
|
|
57
|
+
return /* @__PURE__ */ jsx("th", {
|
|
58
|
+
"data-aui": "table-col",
|
|
59
|
+
"data-aui-align": tableAlignment(column),
|
|
60
|
+
"aria-sort": direction,
|
|
61
|
+
children: onSort ? /* @__PURE__ */ jsxs("button", {
|
|
62
|
+
type: "button",
|
|
63
|
+
"data-aui": "table-sort",
|
|
64
|
+
onClick: () => onSort(i),
|
|
65
|
+
children: [label, direction ? /* @__PURE__ */ jsx("span", {
|
|
66
|
+
"aria-hidden": "true",
|
|
67
|
+
"data-aui": "table-sort-direction",
|
|
68
|
+
children: direction === "ascending" ? "↑" : "↓"
|
|
69
|
+
}) : null]
|
|
70
|
+
}) : label
|
|
71
|
+
}, i);
|
|
72
|
+
}) }) }) : null,
|
|
73
|
+
safeRows.length ? /* @__PURE__ */ jsx("tbody", { children: sortedRows.map((row, r) => /* @__PURE__ */ jsx("tr", { children: row.map((cell, c) => /* @__PURE__ */ jsx("td", {
|
|
74
|
+
"data-aui-align": tableAlignment(safeColumns[c]),
|
|
75
|
+
children: formatValue(cell, isTableColumn(safeColumns[c]) ? safeColumns[c].format : void 0)
|
|
76
|
+
}, c)) }, r)) }) : null,
|
|
77
|
+
children
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function SortableTable(props) {
|
|
82
|
+
const [sort, setSort] = React.useState();
|
|
83
|
+
return /* @__PURE__ */ jsx(TableView, {
|
|
84
|
+
...props,
|
|
85
|
+
sort,
|
|
86
|
+
onSort: (column) => setSort((current) => current?.column !== column ? {
|
|
87
|
+
column,
|
|
88
|
+
direction: "ascending"
|
|
89
|
+
} : current.direction === "ascending" ? {
|
|
90
|
+
column,
|
|
91
|
+
direction: "descending"
|
|
92
|
+
} : void 0)
|
|
93
|
+
});
|
|
94
|
+
}
|
|
13
95
|
const CHART_HEIGHT = 40;
|
|
14
96
|
const CHART_WIDTH = 100;
|
|
15
|
-
const clampValue = (value) => typeof value === "number" && Number.isFinite(value) ?
|
|
16
|
-
const yFor = (value,
|
|
97
|
+
const clampValue = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
98
|
+
const yFor = (value, scale) => {
|
|
99
|
+
const span = scale.max - scale.min;
|
|
100
|
+
return span > 0 ? CHART_HEIGHT - (value - scale.min) / span * CHART_HEIGHT : CHART_HEIGHT;
|
|
101
|
+
};
|
|
17
102
|
const pointSchema = z.object({
|
|
18
103
|
label: z.string().optional().describe("Point label."),
|
|
19
104
|
value: z.number().describe("Point value.")
|
|
20
105
|
});
|
|
21
106
|
const seriesSchema = z.object({
|
|
22
107
|
label: z.string().optional().describe("Series label, shown in the legend."),
|
|
108
|
+
color: z.string().optional().describe("Series color. One of `emphasis`, `secondary`, `alpha-70`, `white`, `white-70`, or `white-50`, matching Text's `color` tokens; other values have no visual effect."),
|
|
23
109
|
data: z.array(pointSchema).describe("Data points for this series.")
|
|
24
110
|
});
|
|
25
111
|
/** Pads every series to the longest series' length, treating a shorter series' missing points as `{ value: 0 }` so mismatched series never misalign or throw. */
|
|
@@ -42,25 +128,46 @@ function normalizeSeries(seriesProp, dataProp) {
|
|
|
42
128
|
}
|
|
43
129
|
return {
|
|
44
130
|
label: typeof s?.label === "string" ? s.label : void 0,
|
|
131
|
+
color: typeof s?.color === "string" ? s.color : void 0,
|
|
45
132
|
values,
|
|
46
133
|
labels
|
|
47
134
|
};
|
|
48
135
|
})
|
|
49
136
|
};
|
|
50
137
|
}
|
|
51
|
-
function
|
|
138
|
+
function valueScale(values) {
|
|
139
|
+
let min = 0;
|
|
140
|
+
let max = 0;
|
|
141
|
+
for (const value of values) {
|
|
142
|
+
min = Math.min(min, value);
|
|
143
|
+
max = Math.max(max, value);
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
min,
|
|
147
|
+
max
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function computeScale(series, count, stacked) {
|
|
52
151
|
if (stacked) {
|
|
152
|
+
let min = 0;
|
|
53
153
|
let max = 0;
|
|
54
154
|
for (let i = 0; i < count; i++) {
|
|
55
|
-
let
|
|
56
|
-
|
|
57
|
-
|
|
155
|
+
let negative = 0;
|
|
156
|
+
let positive = 0;
|
|
157
|
+
for (const s of series) {
|
|
158
|
+
const value = s.values[i] ?? 0;
|
|
159
|
+
if (value < 0) negative += value;
|
|
160
|
+
else positive += value;
|
|
161
|
+
}
|
|
162
|
+
min = Math.min(min, negative);
|
|
163
|
+
max = Math.max(max, positive);
|
|
58
164
|
}
|
|
59
|
-
return
|
|
165
|
+
return {
|
|
166
|
+
min,
|
|
167
|
+
max
|
|
168
|
+
};
|
|
60
169
|
}
|
|
61
|
-
|
|
62
|
-
for (const s of series) for (const v of s.values) max = Math.max(max, v);
|
|
63
|
-
return max;
|
|
170
|
+
return valueScale(series.flatMap((s) => s.values));
|
|
64
171
|
}
|
|
65
172
|
const NICE_MULTIPLES = [
|
|
66
173
|
1,
|
|
@@ -78,100 +185,168 @@ function niceMax(max) {
|
|
|
78
185
|
return 10 ** (exponent + 1);
|
|
79
186
|
}
|
|
80
187
|
const TICK_COUNT = 5;
|
|
81
|
-
|
|
82
|
-
|
|
188
|
+
function axisScale(scale) {
|
|
189
|
+
if (scale.min === 0) return {
|
|
190
|
+
min: 0,
|
|
191
|
+
max: niceMax(scale.max)
|
|
192
|
+
};
|
|
193
|
+
if (scale.max === 0) return {
|
|
194
|
+
min: -niceMax(-scale.min),
|
|
195
|
+
max: 0
|
|
196
|
+
};
|
|
197
|
+
const step = niceMax(Math.max(-scale.min, scale.max) / 2);
|
|
198
|
+
return {
|
|
199
|
+
min: -2 * step,
|
|
200
|
+
max: 2 * step
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/** `TICK_COUNT` evenly spaced ticks from the top of the scale down to its bottom, for a top-to-bottom y-axis column. */
|
|
204
|
+
function tickValues(scale) {
|
|
83
205
|
const ticks = [];
|
|
84
|
-
|
|
206
|
+
if (scale.min === 0) {
|
|
207
|
+
for (let i = 0; i < TICK_COUNT; i++) ticks.push(scale.max * (4 - i) / 4);
|
|
208
|
+
return ticks;
|
|
209
|
+
}
|
|
210
|
+
for (let i = 0; i < TICK_COUNT; i++) ticks.push(scale.min + (scale.max - scale.min) * (4 - i) / 4);
|
|
85
211
|
return ticks;
|
|
86
212
|
}
|
|
87
213
|
function formatTick(value) {
|
|
88
214
|
return (Math.round(value * 100) / 100).toLocaleString("en-US");
|
|
89
215
|
}
|
|
90
216
|
const SERIES_PALETTE_SIZE = 5;
|
|
91
|
-
|
|
217
|
+
const tooltipText = (seriesLabel, pointLabel, index, value) => `${seriesLabel ? `${seriesLabel}, ` : ""}${pointLabel || index + 1}: ${formatTick(value)}`;
|
|
218
|
+
const seriesColor = (series, seriesCount, color) => series.color ?? (seriesCount === 1 && typeof color === "string" ? color : void 0);
|
|
219
|
+
const xFor = (index, count) => count === 1 ? CHART_WIDTH / 2 : index / (count - 1) * CHART_WIDTH;
|
|
220
|
+
function pointTargets(series, positions, count, scale) {
|
|
221
|
+
return series.values.map((value, i) => /* @__PURE__ */ jsx("circle", {
|
|
222
|
+
"data-aui": "chart-point",
|
|
223
|
+
cx: xFor(i, count),
|
|
224
|
+
cy: yFor(positions[i] ?? 0, scale),
|
|
225
|
+
r: 4,
|
|
226
|
+
fill: "transparent",
|
|
227
|
+
children: /* @__PURE__ */ jsx("title", { children: tooltipText(series.label, series.labels[i], i, value) })
|
|
228
|
+
}, i));
|
|
229
|
+
}
|
|
230
|
+
function barGeometry(value, start, scale) {
|
|
231
|
+
const end = start + value;
|
|
232
|
+
if (scale.min === 0 && start >= 0 && end >= 0) {
|
|
233
|
+
const height = scale.max > 0 ? value / scale.max * CHART_HEIGHT : 0;
|
|
234
|
+
const belowHeight = scale.max > 0 ? start / scale.max * CHART_HEIGHT : 0;
|
|
235
|
+
return {
|
|
236
|
+
y: CHART_HEIGHT - belowHeight - height,
|
|
237
|
+
height
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const startY = yFor(start, scale);
|
|
241
|
+
const endY = yFor(end, scale);
|
|
242
|
+
return {
|
|
243
|
+
y: Math.min(startY, endY),
|
|
244
|
+
height: Math.abs(endY - startY)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function renderSeriesMarks(variant, series, count, scale, stacked, color) {
|
|
248
|
+
const seriesCount = series.length;
|
|
92
249
|
if (variant === "bar") {
|
|
93
250
|
const slot = count > 0 ? CHART_WIDTH / count : 0;
|
|
94
251
|
const gap = slot * .2;
|
|
95
252
|
const groupWidth = slot - gap;
|
|
96
|
-
const seriesCount = series.length;
|
|
97
253
|
const perSeriesWidth = stacked || seriesCount <= 1 ? groupWidth : groupWidth / seriesCount;
|
|
98
|
-
const
|
|
254
|
+
const negatives = new Array(count).fill(0);
|
|
255
|
+
const positives = new Array(count).fill(0);
|
|
99
256
|
return series.map((s, seriesIndex) => {
|
|
100
257
|
const marks = s.values.map((value, i) => {
|
|
101
|
-
const height =
|
|
102
|
-
const belowHeight = stacked && scaleMax > 0 ? (cumulative[i] ?? 0) / scaleMax * CHART_HEIGHT : 0;
|
|
258
|
+
const { y, height } = barGeometry(value, stacked ? value < 0 ? negatives[i] ?? 0 : positives[i] ?? 0 : 0, scale);
|
|
103
259
|
const x = stacked || seriesCount <= 1 ? i * slot + gap / 2 : i * slot + gap / 2 + seriesIndex * perSeriesWidth;
|
|
104
260
|
return /* @__PURE__ */ jsx("rect", {
|
|
105
261
|
x,
|
|
106
|
-
y
|
|
262
|
+
y,
|
|
107
263
|
width: perSeriesWidth,
|
|
108
264
|
height,
|
|
109
|
-
fill: "currentColor"
|
|
265
|
+
fill: "currentColor",
|
|
266
|
+
children: /* @__PURE__ */ jsx("title", { children: tooltipText(s.label, s.labels[i], i, value) })
|
|
110
267
|
}, i);
|
|
111
268
|
});
|
|
112
|
-
if (stacked) for (let i = 0; i < count; i++)
|
|
269
|
+
if (stacked) for (let i = 0; i < count; i++) {
|
|
270
|
+
const value = s.values[i] ?? 0;
|
|
271
|
+
if (value < 0) negatives[i] = (negatives[i] ?? 0) + value;
|
|
272
|
+
else positives[i] = (positives[i] ?? 0) + value;
|
|
273
|
+
}
|
|
113
274
|
return /* @__PURE__ */ jsx("g", {
|
|
114
275
|
"data-aui": "chart-series",
|
|
115
276
|
"data-aui-series": seriesIndex % SERIES_PALETTE_SIZE,
|
|
277
|
+
"data-aui-color": seriesColor(s, seriesCount, color),
|
|
116
278
|
children: marks
|
|
117
279
|
}, seriesIndex);
|
|
118
280
|
});
|
|
119
281
|
}
|
|
120
282
|
if (variant === "area") {
|
|
121
|
-
const
|
|
283
|
+
const negatives = new Array(count).fill(0);
|
|
284
|
+
const positives = new Array(count).fill(0);
|
|
122
285
|
return series.map((s, seriesIndex) => {
|
|
123
|
-
const bottoms = stacked ?
|
|
124
|
-
|
|
125
|
-
|
|
286
|
+
const bottoms = s.values.map((value, i) => stacked ? value < 0 ? negatives[i] ?? 0 : positives[i] ?? 0 : 0);
|
|
287
|
+
const tops = s.values.map((value, i) => stacked ? (bottoms[i] ?? 0) + value : value);
|
|
288
|
+
if (stacked) for (let i = 0; i < count; i++) {
|
|
289
|
+
const value = s.values[i] ?? 0;
|
|
290
|
+
if (value < 0) negatives[i] = (negatives[i] ?? 0) + value;
|
|
291
|
+
else positives[i] = (positives[i] ?? 0) + value;
|
|
292
|
+
}
|
|
126
293
|
if (count === 1) {
|
|
127
|
-
const y = yFor(tops[0] ?? 0,
|
|
128
|
-
return /* @__PURE__ */
|
|
294
|
+
const y = yFor(tops[0] ?? 0, scale);
|
|
295
|
+
return /* @__PURE__ */ jsxs("g", {
|
|
129
296
|
"data-aui": "chart-series",
|
|
130
297
|
"data-aui-series": seriesIndex % SERIES_PALETTE_SIZE,
|
|
131
|
-
|
|
298
|
+
"data-aui-color": seriesColor(s, seriesCount, color),
|
|
299
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
132
300
|
cx: CHART_WIDTH / 2,
|
|
133
301
|
cy: y,
|
|
134
302
|
r: 2,
|
|
135
303
|
fill: "currentColor"
|
|
136
|
-
})
|
|
304
|
+
}), pointTargets(s, tops, count, scale)]
|
|
137
305
|
}, seriesIndex);
|
|
138
306
|
}
|
|
139
307
|
if (count === 0) return /* @__PURE__ */ jsx("g", {
|
|
140
308
|
"data-aui": "chart-series",
|
|
141
|
-
"data-aui-series": seriesIndex % SERIES_PALETTE_SIZE
|
|
309
|
+
"data-aui-series": seriesIndex % SERIES_PALETTE_SIZE,
|
|
310
|
+
"data-aui-color": seriesColor(s, seriesCount, color)
|
|
142
311
|
}, seriesIndex);
|
|
143
|
-
const topPoints = tops.map((v, i) => `${i
|
|
144
|
-
const bottomPoints = bottoms.map((v, i) => `${i
|
|
312
|
+
const topPoints = tops.map((v, i) => `${xFor(i, count)},${yFor(v, scale)}`);
|
|
313
|
+
const bottomPoints = bottoms.map((v, i) => `${xFor(i, count)},${yFor(v, scale)}`).reverse();
|
|
145
314
|
return /* @__PURE__ */ jsxs("g", {
|
|
146
315
|
"data-aui": "chart-series",
|
|
147
316
|
"data-aui-series": seriesIndex % SERIES_PALETTE_SIZE,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
317
|
+
"data-aui-color": seriesColor(s, seriesCount, color),
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ jsx("polygon", {
|
|
320
|
+
points: [...topPoints, ...bottomPoints].join(" "),
|
|
321
|
+
fill: "currentColor",
|
|
322
|
+
fillOpacity: "0.25"
|
|
323
|
+
}),
|
|
324
|
+
/* @__PURE__ */ jsx("polyline", {
|
|
325
|
+
points: topPoints.join(" "),
|
|
326
|
+
fill: "none",
|
|
327
|
+
stroke: "currentColor",
|
|
328
|
+
vectorEffect: "non-scaling-stroke"
|
|
329
|
+
}),
|
|
330
|
+
pointTargets(s, tops, count, scale)
|
|
331
|
+
]
|
|
158
332
|
}, seriesIndex);
|
|
159
333
|
});
|
|
160
334
|
}
|
|
161
|
-
return series.map((s, seriesIndex) => /* @__PURE__ */
|
|
335
|
+
return series.map((s, seriesIndex) => /* @__PURE__ */ jsxs("g", {
|
|
162
336
|
"data-aui": "chart-series",
|
|
163
337
|
"data-aui-series": seriesIndex % SERIES_PALETTE_SIZE,
|
|
164
|
-
|
|
338
|
+
"data-aui-color": seriesColor(s, series.length, color),
|
|
339
|
+
children: [count === 1 ? /* @__PURE__ */ jsx("circle", {
|
|
165
340
|
cx: CHART_WIDTH / 2,
|
|
166
|
-
cy: yFor(s.values[0] ?? 0,
|
|
341
|
+
cy: yFor(s.values[0] ?? 0, scale),
|
|
167
342
|
r: 2,
|
|
168
343
|
fill: "currentColor"
|
|
169
344
|
}) : count > 1 ? /* @__PURE__ */ jsx("polyline", {
|
|
170
|
-
points: s.values.map((v, i) => `${i
|
|
345
|
+
points: s.values.map((v, i) => `${xFor(i, count)},${yFor(v, scale)}`).join(" "),
|
|
171
346
|
fill: "none",
|
|
172
347
|
stroke: "currentColor",
|
|
173
348
|
vectorEffect: "non-scaling-stroke"
|
|
174
|
-
}) : null
|
|
349
|
+
}) : null, variant === "line" ? pointTargets(s, s.values, count, scale) : null]
|
|
175
350
|
}, seriesIndex));
|
|
176
351
|
}
|
|
177
352
|
const dataVocabulary = {
|
|
@@ -179,24 +354,18 @@ const dataVocabulary = {
|
|
|
179
354
|
description: "Tabular data. Provide `columns` and `rows`; each row is an array of cells matching the columns.",
|
|
180
355
|
properties: z.object({
|
|
181
356
|
columns: z.array(columnSchema).optional().describe("Column definitions."),
|
|
182
|
-
rows: z.array(z.array(cellSchema)).optional().describe("Rows of cells.")
|
|
357
|
+
rows: z.array(z.array(cellSchema)).optional().describe("Rows of cells."),
|
|
358
|
+
sortable: z.boolean().optional().describe("Allow header sorting.")
|
|
183
359
|
}),
|
|
184
|
-
render: ({ columns, rows, children }) => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
children: isTableColumn(column) ? column.label : ""
|
|
194
|
-
}, i)) }) }) : null,
|
|
195
|
-
safeRows.length ? /* @__PURE__ */ jsx("tbody", { children: safeRows.map((row, r) => /* @__PURE__ */ jsx("tr", { children: row.map((cell, c) => /* @__PURE__ */ jsx("td", { children: isTableCell(cell) ? String(cell) : "" }, c)) }, r)) }) : null,
|
|
196
|
-
children
|
|
197
|
-
]
|
|
198
|
-
});
|
|
199
|
-
}
|
|
360
|
+
render: ({ columns, rows, sortable, children }) => sortable === true ? /* @__PURE__ */ jsx(SortableTable, {
|
|
361
|
+
columns,
|
|
362
|
+
rows,
|
|
363
|
+
children
|
|
364
|
+
}) : /* @__PURE__ */ jsx(TableView, {
|
|
365
|
+
columns,
|
|
366
|
+
rows,
|
|
367
|
+
children
|
|
368
|
+
})
|
|
200
369
|
},
|
|
201
370
|
Markdown: {
|
|
202
371
|
description: "A markdown string. Rendered as-is by default; override this component for a full markdown renderer.",
|
|
@@ -228,11 +397,18 @@ const dataVocabulary = {
|
|
|
228
397
|
const points = Array.isArray(data) ? data : [];
|
|
229
398
|
const n = points.length;
|
|
230
399
|
const values = points.map((d) => clampValue(d?.value));
|
|
231
|
-
const
|
|
400
|
+
const scale = valueScale(values);
|
|
401
|
+
const chartSeries = {
|
|
402
|
+
label: void 0,
|
|
403
|
+
color: void 0,
|
|
404
|
+
values,
|
|
405
|
+
labels: points.map((point) => typeof point?.label === "string" ? point.label : void 0)
|
|
406
|
+
};
|
|
232
407
|
const slot = n > 0 ? CHART_WIDTH / n : 0;
|
|
233
408
|
const gap = slot * .2;
|
|
234
409
|
const barWidth = slot - gap;
|
|
235
|
-
|
|
410
|
+
const crossesZero = scale.min < 0 && scale.max > 0;
|
|
411
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
236
412
|
"data-aui": "chart",
|
|
237
413
|
"data-aui-variant": variant,
|
|
238
414
|
"data-aui-color": color,
|
|
@@ -240,33 +416,43 @@ const dataVocabulary = {
|
|
|
240
416
|
"aria-label": `${variant} chart with ${n} data points`,
|
|
241
417
|
viewBox: `0 0 ${CHART_WIDTH} ${CHART_HEIGHT}`,
|
|
242
418
|
preserveAspectRatio: "none",
|
|
243
|
-
children:
|
|
244
|
-
|
|
419
|
+
children: [crossesZero ? /* @__PURE__ */ jsx("line", {
|
|
420
|
+
"data-aui": "chart-zero",
|
|
421
|
+
x1: 0,
|
|
422
|
+
x2: CHART_WIDTH,
|
|
423
|
+
y1: yFor(0, scale),
|
|
424
|
+
y2: yFor(0, scale),
|
|
425
|
+
stroke: "currentColor",
|
|
426
|
+
vectorEffect: "non-scaling-stroke"
|
|
427
|
+
}) : null, variant === "bar" ? values.map((v, i) => {
|
|
428
|
+
const { y, height } = barGeometry(v, 0, scale);
|
|
245
429
|
return /* @__PURE__ */ jsx("rect", {
|
|
246
430
|
x: i * slot + gap / 2,
|
|
247
|
-
y
|
|
431
|
+
y,
|
|
248
432
|
width: barWidth,
|
|
249
433
|
height,
|
|
250
|
-
fill: "currentColor"
|
|
434
|
+
fill: "currentColor",
|
|
435
|
+
children: /* @__PURE__ */ jsx("title", { children: tooltipText(void 0, chartSeries.labels[i], i, v) })
|
|
251
436
|
}, i);
|
|
252
|
-
}) : n === 1 ? /* @__PURE__ */ jsx("circle", {
|
|
437
|
+
}) : n === 1 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("circle", {
|
|
253
438
|
cx: CHART_WIDTH / 2,
|
|
254
|
-
cy: yFor(values[0] ?? 0,
|
|
439
|
+
cy: yFor(values[0] ?? 0, scale),
|
|
255
440
|
r: 2,
|
|
256
441
|
fill: "currentColor"
|
|
257
|
-
}) : n > 1 ? /* @__PURE__ */ jsx("polyline", {
|
|
258
|
-
points: values.map((v, i) => `${i
|
|
442
|
+
}), variant === "line" ? pointTargets(chartSeries, values, n, scale) : null] }) : n > 1 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("polyline", {
|
|
443
|
+
points: values.map((v, i) => `${xFor(i, n)},${yFor(v, scale)}`).join(" "),
|
|
259
444
|
fill: "none",
|
|
260
445
|
stroke: "currentColor"
|
|
261
|
-
}) : null
|
|
446
|
+
}), variant === "line" ? pointTargets(chartSeries, values, n, scale) : null] }) : null]
|
|
262
447
|
});
|
|
263
448
|
}
|
|
264
449
|
const { count, series: normalized } = normalizeSeries(series, data);
|
|
265
450
|
const stackedScale = !!stacked && (variant === "bar" || variant === "area");
|
|
266
|
-
const
|
|
267
|
-
const
|
|
268
|
-
const marks = renderSeriesMarks(variant, normalized, count,
|
|
269
|
-
const
|
|
451
|
+
const rawScale = computeScale(normalized, count, stackedScale);
|
|
452
|
+
const scale = showAxis ? axisScale(rawScale) : rawScale;
|
|
453
|
+
const marks = renderSeriesMarks(variant, normalized, count, scale, stackedScale, color);
|
|
454
|
+
const crossesZero = rawScale.min < 0 && rawScale.max > 0;
|
|
455
|
+
const svg = /* @__PURE__ */ jsxs("svg", {
|
|
270
456
|
"data-aui": "chart",
|
|
271
457
|
"data-aui-variant": variant,
|
|
272
458
|
"data-aui-color": color,
|
|
@@ -274,7 +460,15 @@ const dataVocabulary = {
|
|
|
274
460
|
"aria-label": `${variant} chart with ${count} data points`,
|
|
275
461
|
viewBox: `0 0 ${CHART_WIDTH} ${CHART_HEIGHT}`,
|
|
276
462
|
preserveAspectRatio: "none",
|
|
277
|
-
children:
|
|
463
|
+
children: [crossesZero ? /* @__PURE__ */ jsx("line", {
|
|
464
|
+
"data-aui": "chart-zero",
|
|
465
|
+
x1: 0,
|
|
466
|
+
x2: CHART_WIDTH,
|
|
467
|
+
y1: yFor(0, scale),
|
|
468
|
+
y2: yFor(0, scale),
|
|
469
|
+
stroke: "currentColor",
|
|
470
|
+
vectorEffect: "non-scaling-stroke"
|
|
471
|
+
}) : null, marks]
|
|
278
472
|
});
|
|
279
473
|
if (!showAxis && !showLegend) return svg;
|
|
280
474
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -282,7 +476,7 @@ const dataVocabulary = {
|
|
|
282
476
|
children: [
|
|
283
477
|
showAxis ? /* @__PURE__ */ jsx("div", {
|
|
284
478
|
"data-aui": "chart-ticks",
|
|
285
|
-
children: tickValues(
|
|
479
|
+
children: tickValues(scale).map((tick, i) => /* @__PURE__ */ jsx("div", { children: formatTick(tick) }, i))
|
|
286
480
|
}) : null,
|
|
287
481
|
svg,
|
|
288
482
|
showAxis ? /* @__PURE__ */ jsx("div", {
|
|
@@ -294,6 +488,7 @@ const dataVocabulary = {
|
|
|
294
488
|
children: normalized.map((s, i) => /* @__PURE__ */ jsxs("span", {
|
|
295
489
|
"data-aui": "chart-legend-item",
|
|
296
490
|
"data-aui-series": i % SERIES_PALETTE_SIZE,
|
|
491
|
+
"data-aui-color": seriesColor(s, normalized.length, color),
|
|
297
492
|
children: [/* @__PURE__ */ jsx("span", { "data-aui": "chart-legend-swatch" }), s.label ?? `Series ${i + 1}`]
|
|
298
493
|
}, i))
|
|
299
494
|
}) : null
|