@assistant-ui/react-generative-ui 0.0.10 → 0.0.12

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.
@@ -0,0 +1,73 @@
1
+ //#region src/a2ui/types.d.ts
2
+ declare const A2UI_SURFACE_ID: unique symbol;
3
+ type A2uiVersion = "v0.9" | "v1.0";
4
+ interface A2uiTemplateChildren {
5
+ readonly template: {
6
+ readonly componentId: string;
7
+ readonly path: string;
8
+ };
9
+ }
10
+ interface ComponentNode extends Record<string, unknown> {
11
+ readonly id: string;
12
+ readonly component: string;
13
+ readonly children?: readonly string[] | A2uiTemplateChildren;
14
+ }
15
+ interface A2uiCreateSurfaceV09Payload {
16
+ readonly surfaceId: string;
17
+ readonly catalogId?: string;
18
+ readonly theme?: unknown;
19
+ readonly attachDataModel?: unknown;
20
+ }
21
+ interface A2uiCreateSurfaceV10Payload {
22
+ readonly surfaceId: string;
23
+ readonly surfaceProperties?: unknown;
24
+ readonly sendDataModel?: unknown;
25
+ readonly components?: readonly ComponentNode[];
26
+ readonly dataModel?: unknown;
27
+ }
28
+ interface A2uiUpdateComponentsPayload {
29
+ readonly surfaceId: string;
30
+ readonly components: readonly ComponentNode[];
31
+ }
32
+ interface A2uiUpdateDataModelPayload {
33
+ readonly surfaceId: string;
34
+ readonly path?: string;
35
+ readonly contents?: unknown;
36
+ readonly value?: unknown;
37
+ readonly data?: unknown;
38
+ }
39
+ interface A2uiDeleteSurfacePayload {
40
+ readonly surfaceId: string;
41
+ }
42
+ type A2uiCreateSurfaceOperation = {
43
+ readonly version: "v0.9";
44
+ readonly createSurface: A2uiCreateSurfaceV09Payload;
45
+ } | {
46
+ readonly version: "v1.0";
47
+ readonly createSurface: A2uiCreateSurfaceV10Payload;
48
+ };
49
+ interface A2uiUpdateComponentsOperation {
50
+ readonly version: A2uiVersion;
51
+ readonly updateComponents: A2uiUpdateComponentsPayload;
52
+ }
53
+ interface A2uiUpdateDataModelOperation {
54
+ readonly version: A2uiVersion;
55
+ readonly updateDataModel: A2uiUpdateDataModelPayload;
56
+ }
57
+ interface A2uiDeleteSurfaceOperation {
58
+ readonly version: A2uiVersion;
59
+ readonly deleteSurface: A2uiDeleteSurfacePayload;
60
+ }
61
+ type A2uiOperation = A2uiCreateSurfaceOperation | A2uiUpdateComponentsOperation | A2uiUpdateDataModelOperation | A2uiDeleteSurfaceOperation;
62
+ type A2uiSurfaceState = {
63
+ components: Map<string, Record<string, unknown>>;
64
+ dataModel: unknown;
65
+ };
66
+ type A2uiState = ReadonlyMap<string, A2uiSurfaceState>;
67
+ interface A2uiOperationResult {
68
+ readonly state: A2uiState;
69
+ readonly warnings: string[];
70
+ }
71
+ //#endregion
72
+ export { A2UI_SURFACE_ID, A2uiCreateSurfaceOperation, A2uiCreateSurfaceV09Payload, A2uiCreateSurfaceV10Payload, A2uiDeleteSurfaceOperation, A2uiDeleteSurfacePayload, A2uiOperation, A2uiOperationResult, A2uiState, A2uiSurfaceState, A2uiTemplateChildren, A2uiUpdateComponentsOperation, A2uiUpdateComponentsPayload, A2uiUpdateDataModelOperation, A2uiUpdateDataModelPayload, A2uiVersion, ComponentNode };
73
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/a2ui/types.ts"],"mappings":";cAAa;KAED;UAEK;WACN;aACE;aACA;;;UAII,sBAAsB;WAC5B;WACA;WACA,+BAA+B;;UAGzB;WACN;WACA;WACA;WACA;;UAGM;WACN;WACA;WACA;WACA,sBAAsB;WACtB;;UAGM;WACN;WACA,qBAAqB;;UAGf;WACN;WACA;WACA;WACA;WACA;;UAGM;WACN;;KAGC;WAEG;WACA,eAAe;;WAGf;WACA,eAAe;;UAGb;WACN,SAAS;WACT,kBAAkB;;UAGZ;WACN,SAAS;WACT,iBAAiB;;UAGX;WACN,SAAS;WACT,eAAe;;KAGd,gBACR,6BACA,gCACA,+BACA;KAEQ;EACV,YAAY,YAAY;EACxB;;KAGU,YAAY,oBAAoB;UAE3B;WACN,OAAO;WACP"}
@@ -0,0 +1,6 @@
1
+ //#region src/a2ui/types.ts
2
+ const A2UI_SURFACE_ID = Symbol("a2uiSurfaceId");
3
+ //#endregion
4
+ export { A2UI_SURFACE_ID };
5
+
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/a2ui/types.ts"],"sourcesContent":["export const A2UI_SURFACE_ID = Symbol(\"a2uiSurfaceId\");\n\nexport type A2uiVersion = \"v0.9\" | \"v1.0\";\n\nexport interface A2uiTemplateChildren {\n readonly template: {\n readonly componentId: string;\n readonly path: string;\n };\n}\n\nexport interface ComponentNode extends Record<string, unknown> {\n readonly id: string;\n readonly component: string;\n readonly children?: readonly string[] | A2uiTemplateChildren;\n}\n\nexport interface A2uiCreateSurfaceV09Payload {\n readonly surfaceId: string;\n readonly catalogId?: string;\n readonly theme?: unknown;\n readonly attachDataModel?: unknown;\n}\n\nexport interface A2uiCreateSurfaceV10Payload {\n readonly surfaceId: string;\n readonly surfaceProperties?: unknown;\n readonly sendDataModel?: unknown;\n readonly components?: readonly ComponentNode[];\n readonly dataModel?: unknown;\n}\n\nexport interface A2uiUpdateComponentsPayload {\n readonly surfaceId: string;\n readonly components: readonly ComponentNode[];\n}\n\nexport interface A2uiUpdateDataModelPayload {\n readonly surfaceId: string;\n readonly path?: string;\n readonly contents?: unknown;\n readonly value?: unknown;\n readonly data?: unknown;\n}\n\nexport interface A2uiDeleteSurfacePayload {\n readonly surfaceId: string;\n}\n\nexport type A2uiCreateSurfaceOperation =\n | {\n readonly version: \"v0.9\";\n readonly createSurface: A2uiCreateSurfaceV09Payload;\n }\n | {\n readonly version: \"v1.0\";\n readonly createSurface: A2uiCreateSurfaceV10Payload;\n };\n\nexport interface A2uiUpdateComponentsOperation {\n readonly version: A2uiVersion;\n readonly updateComponents: A2uiUpdateComponentsPayload;\n}\n\nexport interface A2uiUpdateDataModelOperation {\n readonly version: A2uiVersion;\n readonly updateDataModel: A2uiUpdateDataModelPayload;\n}\n\nexport interface A2uiDeleteSurfaceOperation {\n readonly version: A2uiVersion;\n readonly deleteSurface: A2uiDeleteSurfacePayload;\n}\n\nexport type A2uiOperation =\n | A2uiCreateSurfaceOperation\n | A2uiUpdateComponentsOperation\n | A2uiUpdateDataModelOperation\n | A2uiDeleteSurfaceOperation;\n\nexport type A2uiSurfaceState = {\n components: Map<string, Record<string, unknown>>;\n dataModel: unknown;\n};\n\nexport type A2uiState = ReadonlyMap<string, A2uiSurfaceState>;\n\nexport interface A2uiOperationResult {\n readonly state: A2uiState;\n readonly warnings: string[];\n}\n"],"mappings":";AAAA,MAAa,kBAAkB,OAAO,eAAe"}
package/dist/a2ui.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { A2uiCreateSurfaceOperation, A2uiCreateSurfaceV09Payload, A2uiCreateSurfaceV10Payload, A2uiDeleteSurfaceOperation, A2uiDeleteSurfacePayload, A2uiOperation, A2uiOperationResult, A2uiState, A2uiSurfaceState, A2uiTemplateChildren, A2uiUpdateComponentsOperation, A2uiUpdateComponentsPayload, A2uiUpdateDataModelOperation, A2uiUpdateDataModelPayload, A2uiVersion, ComponentNode } from "./a2ui/types.js";
2
+ import { applyA2uiOperations } from "./a2ui/reducer.js";
3
+ import { convertSurfaceToUISpec } from "./a2ui/convert.js";
4
+ export { type A2uiCreateSurfaceOperation, type A2uiCreateSurfaceV09Payload, type A2uiCreateSurfaceV10Payload, type A2uiDeleteSurfaceOperation, type A2uiDeleteSurfacePayload, type A2uiOperation, type A2uiOperationResult, type A2uiState, type A2uiSurfaceState, type A2uiTemplateChildren, type A2uiUpdateComponentsOperation, type A2uiUpdateComponentsPayload, type A2uiUpdateDataModelOperation, type A2uiUpdateDataModelPayload, type A2uiVersion, type ComponentNode, applyA2uiOperations, convertSurfaceToUISpec };
package/dist/a2ui.js ADDED
@@ -0,0 +1,3 @@
1
+ import { applyA2uiOperations } from "./a2ui/reducer.js";
2
+ import { convertSurfaceToUISpec } from "./a2ui/convert.js";
3
+ export { applyA2uiOperations, convertSurfaceToUISpec };
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","names":[],"sources":["../../src/vocabulary/data.tsx"],"mappings":";;cA8Qa"}
1
+ {"version":3,"file":"data.d.ts","names":[],"sources":["../../src/vocabulary/data.tsx"],"mappings":";;cAoRa"}
@@ -138,15 +138,19 @@ function renderSeriesMarks(variant, series, count, scaleMax, stacked) {
138
138
  }, seriesIndex);
139
139
  const topPoints = tops.map((v, i) => `${i / (count - 1) * CHART_WIDTH},${yFor(v, scaleMax)}`);
140
140
  const bottomPoints = bottoms.map((v, i) => `${i / (count - 1) * CHART_WIDTH},${yFor(v, scaleMax)}`).reverse();
141
- return /* @__PURE__ */ jsx("g", {
141
+ return /* @__PURE__ */ jsxs("g", {
142
142
  "data-aui": "chart-series",
143
143
  "data-aui-series": seriesIndex % SERIES_PALETTE_SIZE,
144
- children: /* @__PURE__ */ jsx("polygon", {
144
+ children: [/* @__PURE__ */ jsx("polygon", {
145
145
  points: [...topPoints, ...bottomPoints].join(" "),
146
146
  fill: "currentColor",
147
- fillOpacity: "0.25",
148
- stroke: "currentColor"
149
- })
147
+ fillOpacity: "0.25"
148
+ }), /* @__PURE__ */ jsx("polyline", {
149
+ points: topPoints.join(" "),
150
+ fill: "none",
151
+ stroke: "currentColor",
152
+ vectorEffect: "non-scaling-stroke"
153
+ })]
150
154
  }, seriesIndex);
151
155
  });
152
156
  }
@@ -161,7 +165,8 @@ function renderSeriesMarks(variant, series, count, scaleMax, stacked) {
161
165
  }) : count > 1 ? /* @__PURE__ */ jsx("polyline", {
162
166
  points: s.values.map((v, i) => `${i / (count - 1) * CHART_WIDTH},${yFor(v, scaleMax)}`).join(" "),
163
167
  fill: "none",
164
- stroke: "currentColor"
168
+ stroke: "currentColor",
169
+ vectorEffect: "non-scaling-stroke"
165
170
  }) : null
166
171
  }, seriesIndex));
167
172
  }
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","names":[],"sources":["../../src/vocabulary/data.tsx"],"sourcesContent":["import { z } from \"zod\";\nimport type { GenerativeUILibrary } from \"../types\";\n\nconst columnSchema = z.object({\n label: z.string().describe(\"Column header label.\"),\n});\n\nconst cellSchema = z\n .union([z.string(), z.number(), z.boolean()])\n .describe(\"A cell value.\");\n\nconst CHART_HEIGHT = 40;\nconst CHART_WIDTH = 100;\n\nconst clampValue = (value: unknown): number =>\n typeof value === \"number\" && Number.isFinite(value) ? Math.max(0, value) : 0;\n\nconst yFor = (value: number, max: number): number =>\n max > 0 ? CHART_HEIGHT - (value / max) * CHART_HEIGHT : CHART_HEIGHT;\n\nconst pointSchema = z.object({\n label: z.string().optional().describe(\"Point label.\"),\n value: z.number().describe(\"Point value.\"),\n});\n\nconst seriesSchema = z.object({\n label: z.string().optional().describe(\"Series label, shown in the legend.\"),\n data: z.array(pointSchema).describe(\"Data points for this series.\"),\n});\n\ntype ChartPoint = { label?: string; value: number };\ntype ChartSeriesInput = { label?: string; data: ChartPoint[] };\ntype NormalizedChartSeries = {\n label: string | undefined;\n values: number[];\n labels: (string | undefined)[];\n};\n\n/** Pads every series to the longest series' length, treating a shorter series' missing points as `{ value: 0 }` so mismatched series never misalign or throw. */\nfunction normalizeSeries(\n seriesProp: unknown,\n dataProp: unknown,\n): { count: number; series: NormalizedChartSeries[] } {\n const rawSeries: ChartSeriesInput[] =\n Array.isArray(seriesProp) && seriesProp.length > 0\n ? (seriesProp as ChartSeriesInput[])\n : [{ data: Array.isArray(dataProp) ? (dataProp as ChartPoint[]) : [] }];\n\n const count = rawSeries.reduce((max, s) => {\n const len = Array.isArray(s?.data) ? s.data.length : 0;\n return Math.max(max, len);\n }, 0);\n\n const series = rawSeries.map((s) => {\n const points = Array.isArray(s?.data) ? s.data : [];\n const values: number[] = [];\n const labels: (string | undefined)[] = [];\n for (let i = 0; i < count; i++) {\n const point = points[i];\n values.push(clampValue(point?.value));\n labels.push(typeof point?.label === \"string\" ? point.label : undefined);\n }\n return {\n label: typeof s?.label === \"string\" ? s.label : undefined,\n values,\n labels,\n };\n });\n\n return { count, series };\n}\n\nfunction computeMax(\n series: NormalizedChartSeries[],\n count: number,\n stacked: boolean,\n): number {\n if (stacked) {\n let max = 0;\n for (let i = 0; i < count; i++) {\n let sum = 0;\n for (const s of series) sum += s.values[i] ?? 0;\n max = Math.max(max, sum);\n }\n return max;\n }\n let max = 0;\n for (const s of series) for (const v of s.values) max = Math.max(max, v);\n return max;\n}\n\nconst NICE_MULTIPLES = [1, 2, 5];\n\n/** The smallest of `{1, 2, 5} × 10^n` that is `>= max`, so axis ticks land on round numbers. */\nfunction niceMax(max: number): number {\n if (max <= 0) return 0;\n const exponent = Math.floor(Math.log10(max));\n for (const multiple of NICE_MULTIPLES) {\n const candidate = multiple * 10 ** exponent;\n if (candidate >= max) return candidate;\n }\n return 10 ** (exponent + 1);\n}\n\nconst TICK_COUNT = 5;\n\n/** `TICK_COUNT` evenly spaced ticks from `max` down to `0`, for a top-to-bottom y-axis column. */\nfunction tickValues(max: number): number[] {\n const ticks: number[] = [];\n for (let i = 0; i < TICK_COUNT; i++) {\n ticks.push((max * (TICK_COUNT - 1 - i)) / (TICK_COUNT - 1));\n }\n return ticks;\n}\n\nfunction formatTick(value: number): string {\n return (Math.round(value * 100) / 100).toLocaleString(\"en-US\");\n}\n\ntype ChartVariant = \"bar\" | \"line\" | \"sparkline\" | \"area\";\n\nconst SERIES_PALETTE_SIZE = 5;\n\nfunction renderSeriesMarks(\n variant: ChartVariant,\n series: NormalizedChartSeries[],\n count: number,\n scaleMax: number,\n stacked: boolean,\n) {\n if (variant === \"bar\") {\n const slot = count > 0 ? CHART_WIDTH / count : 0;\n const gap = slot * 0.2;\n const groupWidth = slot - gap;\n const seriesCount = series.length;\n const perSeriesWidth =\n stacked || seriesCount <= 1 ? groupWidth : groupWidth / seriesCount;\n const cumulative = new Array(count).fill(0) as number[];\n\n return series.map((s, seriesIndex) => {\n const marks = s.values.map((value, i) => {\n const height = scaleMax > 0 ? (value / scaleMax) * CHART_HEIGHT : 0;\n const belowHeight =\n stacked && scaleMax > 0\n ? ((cumulative[i] ?? 0) / scaleMax) * CHART_HEIGHT\n : 0;\n const x =\n stacked || seriesCount <= 1\n ? i * slot + gap / 2\n : i * slot + gap / 2 + seriesIndex * perSeriesWidth;\n return (\n <rect\n key={i}\n x={x}\n y={CHART_HEIGHT - belowHeight - height}\n width={perSeriesWidth}\n height={height}\n fill=\"currentColor\"\n />\n );\n });\n if (stacked) {\n for (let i = 0; i < count; i++) {\n cumulative[i] = (cumulative[i] ?? 0) + (s.values[i] ?? 0);\n }\n }\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n {marks}\n </g>\n );\n });\n }\n\n if (variant === \"area\") {\n const cumulative = new Array(count).fill(0) as number[];\n\n return series.map((s, seriesIndex) => {\n const bottoms = stacked\n ? cumulative.slice()\n : (new Array(count).fill(0) as number[]);\n if (stacked) {\n for (let i = 0; i < count; i++) {\n cumulative[i] = (cumulative[i] ?? 0) + (s.values[i] ?? 0);\n }\n }\n const tops = stacked ? cumulative.slice() : s.values.slice();\n\n if (count === 1) {\n const y = yFor(tops[0] ?? 0, scaleMax);\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n <circle cx={CHART_WIDTH / 2} cy={y} r={2} fill=\"currentColor\" />\n </g>\n );\n }\n if (count === 0) {\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n />\n );\n }\n\n const topPoints = tops.map(\n (v, i) => `${(i / (count - 1)) * CHART_WIDTH},${yFor(v, scaleMax)}`,\n );\n const bottomPoints = bottoms\n .map(\n (v, i) => `${(i / (count - 1)) * CHART_WIDTH},${yFor(v, scaleMax)}`,\n )\n .reverse();\n\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n <polygon\n points={[...topPoints, ...bottomPoints].join(\" \")}\n fill=\"currentColor\"\n fillOpacity=\"0.25\"\n stroke=\"currentColor\"\n />\n </g>\n );\n });\n }\n\n // line / sparkline: each series is always drawn independently. Stacking a line has no single standard meaning, so `stacked` is ignored (the caller never passes it for these variants).\n return series.map((s, seriesIndex) => (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n {count === 1 ? (\n <circle\n cx={CHART_WIDTH / 2}\n cy={yFor(s.values[0] ?? 0, scaleMax)}\n r={2}\n fill=\"currentColor\"\n />\n ) : count > 1 ? (\n <polyline\n points={s.values\n .map(\n (v, i) =>\n `${(i / (count - 1)) * CHART_WIDTH},${yFor(v, scaleMax)}`,\n )\n .join(\" \")}\n fill=\"none\"\n stroke=\"currentColor\"\n />\n ) : null}\n </g>\n ));\n}\n\nexport const dataVocabulary = {\n Table: {\n description:\n \"Tabular data. Provide `columns` and `rows`; each row is an array of cells matching the columns.\",\n properties: z.object({\n columns: z.array(columnSchema).optional().describe(\"Column definitions.\"),\n rows: z.array(z.array(cellSchema)).optional().describe(\"Rows of cells.\"),\n }),\n render: ({ columns, rows, children }) => (\n <table data-aui=\"table\">\n {columns?.length ? (\n <thead>\n <tr>\n {columns.map((c: { label: string }, i: number) => (\n <th key={i} data-aui=\"table-col\">\n {c.label}\n </th>\n ))}\n </tr>\n </thead>\n ) : null}\n {rows?.length ? (\n <tbody>\n {rows.map((row: (string | number | boolean)[], r: number) => (\n <tr key={r}>\n {row.map((cell: string | number | boolean, c: number) => (\n <td key={c}>{String(cell)}</td>\n ))}\n </tr>\n ))}\n </tbody>\n ) : null}\n {children}\n </table>\n ),\n },\n Markdown: {\n description:\n \"A markdown string. Rendered as-is by default; override this component for a full markdown renderer.\",\n properties: z.object({\n value: z.string().describe(\"Markdown source.\"),\n }),\n streamProperties: true,\n render: ({ value, children }) => (\n <div data-aui=\"markdown\">\n {value}\n {children}\n </div>\n ),\n },\n Chart: {\n description:\n \"A chart. `variant` selects bar, line, sparkline, or area rendering. Provide `data` for a single series, or `series` for multiple named series (`series` takes precedence over `data` when both are present). Set `stacked` to accumulate series values instead of overlaying them, and `showAxis`/`showLegend` to add y-axis ticks, x-axis point labels, and a legend.\",\n properties: z.object({\n variant: z\n .enum([\"bar\", \"line\", \"sparkline\", \"area\"])\n .describe(\"Chart variant.\"),\n data: z\n .array(pointSchema)\n .optional()\n .describe(\"Data points for a single series.\"),\n series: z\n .array(seriesSchema)\n .optional()\n .describe(\n \"Multiple named series; takes precedence over `data` when present.\",\n ),\n stacked: z\n .boolean()\n .optional()\n .describe(\n \"Accumulate series values instead of overlaying them (bar and area variants; ignored for line and sparkline).\",\n ),\n showAxis: z\n .boolean()\n .optional()\n .describe(\"Show y-axis ticks and x-axis point labels.\"),\n showLegend: z\n .boolean()\n .optional()\n .describe(\"Show a legend mapping each series to its color.\"),\n color: z\n .string()\n .optional()\n .describe(\n \"Series color (single-series mode only). One of `emphasis`, `secondary`, `alpha-70`, `white`, `white-70`, or `white-50`, matching Text's `color` tokens; other values have no visual effect.\",\n ),\n }),\n render: ({\n variant,\n data,\n series,\n stacked,\n showAxis,\n showLegend,\n color,\n }) => {\n const usesExtendedFeatures =\n variant === \"area\" ||\n !!stacked ||\n !!showAxis ||\n !!showLegend ||\n (Array.isArray(series) && series.length > 0);\n\n if (!usesExtendedFeatures) {\n const points = Array.isArray(data) ? data : [];\n const n = points.length;\n const values = points.map((d) => clampValue(d?.value));\n const max = values.reduce((m, v) => Math.max(m, v), 0);\n const slot = n > 0 ? CHART_WIDTH / n : 0;\n const gap = slot * 0.2;\n const barWidth = slot - gap;\n\n return (\n <svg\n data-aui=\"chart\"\n data-aui-variant={variant}\n data-aui-color={color}\n role=\"img\"\n aria-label={`${variant} chart with ${n} data points`}\n viewBox={`0 0 ${CHART_WIDTH} ${CHART_HEIGHT}`}\n preserveAspectRatio=\"none\"\n >\n {variant === \"bar\" ? (\n values.map((v, i) => {\n const height = max > 0 ? (v / max) * CHART_HEIGHT : 0;\n return (\n <rect\n key={i}\n x={i * slot + gap / 2}\n y={CHART_HEIGHT - height}\n width={barWidth}\n height={height}\n fill=\"currentColor\"\n />\n );\n })\n ) : n === 1 ? (\n <circle\n cx={CHART_WIDTH / 2}\n cy={yFor(values[0] ?? 0, max)}\n r={2}\n fill=\"currentColor\"\n />\n ) : n > 1 ? (\n <polyline\n points={values\n .map(\n (v, i) => `${(i / (n - 1)) * CHART_WIDTH},${yFor(v, max)}`,\n )\n .join(\" \")}\n fill=\"none\"\n stroke=\"currentColor\"\n />\n ) : null}\n </svg>\n );\n }\n\n const { count, series: normalized } = normalizeSeries(series, data);\n const stackedScale =\n !!stacked && (variant === \"bar\" || variant === \"area\");\n const rawMax = computeMax(normalized, count, stackedScale);\n const scaleMax = showAxis ? niceMax(rawMax) : rawMax;\n const marks = renderSeriesMarks(\n variant,\n normalized,\n count,\n scaleMax,\n stackedScale,\n );\n\n const svg = (\n <svg\n data-aui=\"chart\"\n data-aui-variant={variant}\n data-aui-color={color}\n role=\"img\"\n aria-label={`${variant} chart with ${count} data points`}\n viewBox={`0 0 ${CHART_WIDTH} ${CHART_HEIGHT}`}\n preserveAspectRatio=\"none\"\n >\n {marks}\n </svg>\n );\n\n if (!showAxis && !showLegend) return svg;\n\n return (\n <div data-aui=\"chart-frame\">\n {showAxis ? (\n <div data-aui=\"chart-ticks\">\n {tickValues(scaleMax).map((tick, i) => (\n <div key={i}>{formatTick(tick)}</div>\n ))}\n </div>\n ) : null}\n {svg}\n {showAxis ? (\n <div data-aui=\"chart-xlabels\">\n {(normalized[0]?.labels ?? []).map((label, i) => (\n <div key={i}>{label ?? \"\"}</div>\n ))}\n </div>\n ) : null}\n {showLegend ? (\n <div data-aui=\"chart-legend\">\n {normalized.map((s, i) => (\n <span\n key={i}\n data-aui=\"chart-legend-item\"\n data-aui-series={i % SERIES_PALETTE_SIZE}\n >\n <span data-aui=\"chart-legend-swatch\" />\n {s.label ?? `Series ${i + 1}`}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n );\n },\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":"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"}
1
+ {"version":3,"file":"data.js","names":[],"sources":["../../src/vocabulary/data.tsx"],"sourcesContent":["import { z } from \"zod\";\nimport type { GenerativeUILibrary } from \"../types\";\n\nconst columnSchema = z.object({\n label: z.string().describe(\"Column header label.\"),\n});\n\nconst cellSchema = z\n .union([z.string(), z.number(), z.boolean()])\n .describe(\"A cell value.\");\n\nconst CHART_HEIGHT = 40;\nconst CHART_WIDTH = 100;\n\nconst clampValue = (value: unknown): number =>\n typeof value === \"number\" && Number.isFinite(value) ? Math.max(0, value) : 0;\n\nconst yFor = (value: number, max: number): number =>\n max > 0 ? CHART_HEIGHT - (value / max) * CHART_HEIGHT : CHART_HEIGHT;\n\nconst pointSchema = z.object({\n label: z.string().optional().describe(\"Point label.\"),\n value: z.number().describe(\"Point value.\"),\n});\n\nconst seriesSchema = z.object({\n label: z.string().optional().describe(\"Series label, shown in the legend.\"),\n data: z.array(pointSchema).describe(\"Data points for this series.\"),\n});\n\ntype ChartPoint = { label?: string; value: number };\ntype ChartSeriesInput = { label?: string; data: ChartPoint[] };\ntype NormalizedChartSeries = {\n label: string | undefined;\n values: number[];\n labels: (string | undefined)[];\n};\n\n/** Pads every series to the longest series' length, treating a shorter series' missing points as `{ value: 0 }` so mismatched series never misalign or throw. */\nfunction normalizeSeries(\n seriesProp: unknown,\n dataProp: unknown,\n): { count: number; series: NormalizedChartSeries[] } {\n const rawSeries: ChartSeriesInput[] =\n Array.isArray(seriesProp) && seriesProp.length > 0\n ? (seriesProp as ChartSeriesInput[])\n : [{ data: Array.isArray(dataProp) ? (dataProp as ChartPoint[]) : [] }];\n\n const count = rawSeries.reduce((max, s) => {\n const len = Array.isArray(s?.data) ? s.data.length : 0;\n return Math.max(max, len);\n }, 0);\n\n const series = rawSeries.map((s) => {\n const points = Array.isArray(s?.data) ? s.data : [];\n const values: number[] = [];\n const labels: (string | undefined)[] = [];\n for (let i = 0; i < count; i++) {\n const point = points[i];\n values.push(clampValue(point?.value));\n labels.push(typeof point?.label === \"string\" ? point.label : undefined);\n }\n return {\n label: typeof s?.label === \"string\" ? s.label : undefined,\n values,\n labels,\n };\n });\n\n return { count, series };\n}\n\nfunction computeMax(\n series: NormalizedChartSeries[],\n count: number,\n stacked: boolean,\n): number {\n if (stacked) {\n let max = 0;\n for (let i = 0; i < count; i++) {\n let sum = 0;\n for (const s of series) sum += s.values[i] ?? 0;\n max = Math.max(max, sum);\n }\n return max;\n }\n let max = 0;\n for (const s of series) for (const v of s.values) max = Math.max(max, v);\n return max;\n}\n\nconst NICE_MULTIPLES = [1, 2, 5];\n\n/** The smallest of `{1, 2, 5} × 10^n` that is `>= max`, so axis ticks land on round numbers. */\nfunction niceMax(max: number): number {\n if (max <= 0) return 0;\n const exponent = Math.floor(Math.log10(max));\n for (const multiple of NICE_MULTIPLES) {\n const candidate = multiple * 10 ** exponent;\n if (candidate >= max) return candidate;\n }\n return 10 ** (exponent + 1);\n}\n\nconst TICK_COUNT = 5;\n\n/** `TICK_COUNT` evenly spaced ticks from `max` down to `0`, for a top-to-bottom y-axis column. */\nfunction tickValues(max: number): number[] {\n const ticks: number[] = [];\n for (let i = 0; i < TICK_COUNT; i++) {\n ticks.push((max * (TICK_COUNT - 1 - i)) / (TICK_COUNT - 1));\n }\n return ticks;\n}\n\nfunction formatTick(value: number): string {\n return (Math.round(value * 100) / 100).toLocaleString(\"en-US\");\n}\n\ntype ChartVariant = \"bar\" | \"line\" | \"sparkline\" | \"area\";\n\nconst SERIES_PALETTE_SIZE = 5;\n\nfunction renderSeriesMarks(\n variant: ChartVariant,\n series: NormalizedChartSeries[],\n count: number,\n scaleMax: number,\n stacked: boolean,\n) {\n if (variant === \"bar\") {\n const slot = count > 0 ? CHART_WIDTH / count : 0;\n const gap = slot * 0.2;\n const groupWidth = slot - gap;\n const seriesCount = series.length;\n const perSeriesWidth =\n stacked || seriesCount <= 1 ? groupWidth : groupWidth / seriesCount;\n const cumulative = new Array(count).fill(0) as number[];\n\n return series.map((s, seriesIndex) => {\n const marks = s.values.map((value, i) => {\n const height = scaleMax > 0 ? (value / scaleMax) * CHART_HEIGHT : 0;\n const belowHeight =\n stacked && scaleMax > 0\n ? ((cumulative[i] ?? 0) / scaleMax) * CHART_HEIGHT\n : 0;\n const x =\n stacked || seriesCount <= 1\n ? i * slot + gap / 2\n : i * slot + gap / 2 + seriesIndex * perSeriesWidth;\n return (\n <rect\n key={i}\n x={x}\n y={CHART_HEIGHT - belowHeight - height}\n width={perSeriesWidth}\n height={height}\n fill=\"currentColor\"\n />\n );\n });\n if (stacked) {\n for (let i = 0; i < count; i++) {\n cumulative[i] = (cumulative[i] ?? 0) + (s.values[i] ?? 0);\n }\n }\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n {marks}\n </g>\n );\n });\n }\n\n if (variant === \"area\") {\n const cumulative = new Array(count).fill(0) as number[];\n\n return series.map((s, seriesIndex) => {\n const bottoms = stacked\n ? cumulative.slice()\n : (new Array(count).fill(0) as number[]);\n if (stacked) {\n for (let i = 0; i < count; i++) {\n cumulative[i] = (cumulative[i] ?? 0) + (s.values[i] ?? 0);\n }\n }\n const tops = stacked ? cumulative.slice() : s.values.slice();\n\n if (count === 1) {\n const y = yFor(tops[0] ?? 0, scaleMax);\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n <circle cx={CHART_WIDTH / 2} cy={y} r={2} fill=\"currentColor\" />\n </g>\n );\n }\n if (count === 0) {\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n />\n );\n }\n\n const topPoints = tops.map(\n (v, i) => `${(i / (count - 1)) * CHART_WIDTH},${yFor(v, scaleMax)}`,\n );\n const bottomPoints = bottoms\n .map(\n (v, i) => `${(i / (count - 1)) * CHART_WIDTH},${yFor(v, scaleMax)}`,\n )\n .reverse();\n\n return (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n <polygon\n points={[...topPoints, ...bottomPoints].join(\" \")}\n fill=\"currentColor\"\n fillOpacity=\"0.25\"\n />\n <polyline\n points={topPoints.join(\" \")}\n fill=\"none\"\n stroke=\"currentColor\"\n vectorEffect=\"non-scaling-stroke\"\n />\n </g>\n );\n });\n }\n\n // line / sparkline: each series is always drawn independently. Stacking a line has no single standard meaning, so `stacked` is ignored (the caller never passes it for these variants).\n return series.map((s, seriesIndex) => (\n <g\n key={seriesIndex}\n data-aui=\"chart-series\"\n data-aui-series={seriesIndex % SERIES_PALETTE_SIZE}\n >\n {count === 1 ? (\n <circle\n cx={CHART_WIDTH / 2}\n cy={yFor(s.values[0] ?? 0, scaleMax)}\n r={2}\n fill=\"currentColor\"\n />\n ) : count > 1 ? (\n <polyline\n points={s.values\n .map(\n (v, i) =>\n `${(i / (count - 1)) * CHART_WIDTH},${yFor(v, scaleMax)}`,\n )\n .join(\" \")}\n fill=\"none\"\n stroke=\"currentColor\"\n vectorEffect=\"non-scaling-stroke\"\n />\n ) : null}\n </g>\n ));\n}\n\nexport const dataVocabulary = {\n Table: {\n description:\n \"Tabular data. Provide `columns` and `rows`; each row is an array of cells matching the columns.\",\n properties: z.object({\n columns: z.array(columnSchema).optional().describe(\"Column definitions.\"),\n rows: z.array(z.array(cellSchema)).optional().describe(\"Rows of cells.\"),\n }),\n render: ({ columns, rows, children }) => (\n <table data-aui=\"table\">\n {columns?.length ? (\n <thead>\n <tr>\n {columns.map((c: { label: string }, i: number) => (\n <th key={i} data-aui=\"table-col\">\n {c.label}\n </th>\n ))}\n </tr>\n </thead>\n ) : null}\n {rows?.length ? (\n <tbody>\n {rows.map((row: (string | number | boolean)[], r: number) => (\n <tr key={r}>\n {row.map((cell: string | number | boolean, c: number) => (\n <td key={c}>{String(cell)}</td>\n ))}\n </tr>\n ))}\n </tbody>\n ) : null}\n {children}\n </table>\n ),\n },\n Markdown: {\n description:\n \"A markdown string. Rendered as-is by default; override this component for a full markdown renderer.\",\n properties: z.object({\n value: z.string().describe(\"Markdown source.\"),\n }),\n streamProperties: true,\n render: ({ value, children }) => (\n <div data-aui=\"markdown\">\n {value}\n {children}\n </div>\n ),\n },\n Chart: {\n description:\n \"A chart. `variant` selects bar, line, sparkline, or area rendering. Provide `data` for a single series, or `series` for multiple named series (`series` takes precedence over `data` when both are present). Set `stacked` to accumulate series values instead of overlaying them, and `showAxis`/`showLegend` to add y-axis ticks, x-axis point labels, and a legend.\",\n properties: z.object({\n variant: z\n .enum([\"bar\", \"line\", \"sparkline\", \"area\"])\n .describe(\"Chart variant.\"),\n data: z\n .array(pointSchema)\n .optional()\n .describe(\"Data points for a single series.\"),\n series: z\n .array(seriesSchema)\n .optional()\n .describe(\n \"Multiple named series; takes precedence over `data` when present.\",\n ),\n stacked: z\n .boolean()\n .optional()\n .describe(\n \"Accumulate series values instead of overlaying them (bar and area variants; ignored for line and sparkline).\",\n ),\n showAxis: z\n .boolean()\n .optional()\n .describe(\"Show y-axis ticks and x-axis point labels.\"),\n showLegend: z\n .boolean()\n .optional()\n .describe(\"Show a legend mapping each series to its color.\"),\n color: z\n .string()\n .optional()\n .describe(\n \"Series color (single-series mode only). One of `emphasis`, `secondary`, `alpha-70`, `white`, `white-70`, or `white-50`, matching Text's `color` tokens; other values have no visual effect.\",\n ),\n }),\n render: ({\n variant,\n data,\n series,\n stacked,\n showAxis,\n showLegend,\n color,\n }) => {\n const usesExtendedFeatures =\n variant === \"area\" ||\n !!stacked ||\n !!showAxis ||\n !!showLegend ||\n (Array.isArray(series) && series.length > 0);\n\n if (!usesExtendedFeatures) {\n const points = Array.isArray(data) ? data : [];\n const n = points.length;\n const values = points.map((d) => clampValue(d?.value));\n const max = values.reduce((m, v) => Math.max(m, v), 0);\n const slot = n > 0 ? CHART_WIDTH / n : 0;\n const gap = slot * 0.2;\n const barWidth = slot - gap;\n\n return (\n <svg\n data-aui=\"chart\"\n data-aui-variant={variant}\n data-aui-color={color}\n role=\"img\"\n aria-label={`${variant} chart with ${n} data points`}\n viewBox={`0 0 ${CHART_WIDTH} ${CHART_HEIGHT}`}\n preserveAspectRatio=\"none\"\n >\n {variant === \"bar\" ? (\n values.map((v, i) => {\n const height = max > 0 ? (v / max) * CHART_HEIGHT : 0;\n return (\n <rect\n key={i}\n x={i * slot + gap / 2}\n y={CHART_HEIGHT - height}\n width={barWidth}\n height={height}\n fill=\"currentColor\"\n />\n );\n })\n ) : n === 1 ? (\n <circle\n cx={CHART_WIDTH / 2}\n cy={yFor(values[0] ?? 0, max)}\n r={2}\n fill=\"currentColor\"\n />\n ) : n > 1 ? (\n <polyline\n points={values\n .map(\n (v, i) => `${(i / (n - 1)) * CHART_WIDTH},${yFor(v, max)}`,\n )\n .join(\" \")}\n fill=\"none\"\n stroke=\"currentColor\"\n />\n ) : null}\n </svg>\n );\n }\n\n const { count, series: normalized } = normalizeSeries(series, data);\n const stackedScale =\n !!stacked && (variant === \"bar\" || variant === \"area\");\n const rawMax = computeMax(normalized, count, stackedScale);\n const scaleMax = showAxis ? niceMax(rawMax) : rawMax;\n const marks = renderSeriesMarks(\n variant,\n normalized,\n count,\n scaleMax,\n stackedScale,\n );\n\n const svg = (\n <svg\n data-aui=\"chart\"\n data-aui-variant={variant}\n data-aui-color={color}\n role=\"img\"\n aria-label={`${variant} chart with ${count} data points`}\n viewBox={`0 0 ${CHART_WIDTH} ${CHART_HEIGHT}`}\n preserveAspectRatio=\"none\"\n >\n {marks}\n </svg>\n );\n\n if (!showAxis && !showLegend) return svg;\n\n return (\n <div data-aui=\"chart-frame\">\n {showAxis ? (\n <div data-aui=\"chart-ticks\">\n {tickValues(scaleMax).map((tick, i) => (\n <div key={i}>{formatTick(tick)}</div>\n ))}\n </div>\n ) : null}\n {svg}\n {showAxis ? (\n <div data-aui=\"chart-xlabels\">\n {(normalized[0]?.labels ?? []).map((label, i) => (\n <div key={i}>{label ?? \"\"}</div>\n ))}\n </div>\n ) : null}\n {showLegend ? (\n <div data-aui=\"chart-legend\">\n {normalized.map((s, i) => (\n <span\n key={i}\n data-aui=\"chart-legend-item\"\n data-aui-series={i % SERIES_PALETTE_SIZE}\n >\n <span data-aui=\"chart-legend-swatch\" />\n {s.label ?? `Series ${i + 1}`}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n );\n },\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-generative-ui",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Generative UI components for assistant-ui",
5
5
  "keywords": [
6
6
  "generative-ui",
@@ -28,6 +28,10 @@
28
28
  "types": "./dist/ir.d.ts",
29
29
  "default": "./dist/ir.js"
30
30
  },
31
+ "./a2ui": {
32
+ "types": "./dist/a2ui.d.ts",
33
+ "default": "./dist/a2ui.js"
34
+ },
31
35
  "./slack": {
32
36
  "types": "./dist/slack.d.ts",
33
37
  "default": "./dist/slack.js"
@@ -46,7 +50,7 @@
46
50
  ],
47
51
  "sideEffects": false,
48
52
  "dependencies": {
49
- "assistant-stream": "^0.3.29"
53
+ "assistant-stream": "^0.3.34"
50
54
  },
51
55
  "peerDependencies": {
52
56
  "@assistant-ui/react": "^0.15.0",
@@ -66,8 +70,8 @@
66
70
  "react-dom": "^19.2.8",
67
71
  "vitest": "^4.1.10",
68
72
  "zod": "^4.4.3",
69
- "@assistant-ui/react": "0.15.0",
70
- "@assistant-ui/x-buildutils": "0.0.20"
73
+ "@assistant-ui/react": "0.15.5",
74
+ "@assistant-ui/x-buildutils": "0.0.21"
71
75
  },
72
76
  "publishConfig": {
73
77
  "access": "public",
@@ -0,0 +1,345 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { UIElement } from "../ir";
3
+ import { convertSurfaceToUISpec } from "./convert";
4
+ import { applyA2uiOperations } from "./reducer";
5
+ import type { A2uiSurfaceState } from "./types";
6
+
7
+ const surfaceFrom = (
8
+ components: readonly Record<string, unknown>[],
9
+ dataModel: unknown = {},
10
+ ): A2uiSurfaceState => ({
11
+ components: new Map(
12
+ components.map((component) => [
13
+ component["id"] as string,
14
+ { ...component },
15
+ ]),
16
+ ),
17
+ dataModel,
18
+ });
19
+
20
+ describe("convertSurfaceToUISpec", () => {
21
+ it("converts an operation-built A2UI surface to the exact canonical UISpec", () => {
22
+ const result = applyA2uiOperations(new Map(), [
23
+ {
24
+ version: "v0.9",
25
+ createSurface: { surfaceId: "main" },
26
+ },
27
+ {
28
+ version: "v0.9",
29
+ updateComponents: {
30
+ surfaceId: "main",
31
+ components: [
32
+ {
33
+ id: "root",
34
+ component: "Column",
35
+ gap: 2,
36
+ children: [
37
+ "heading",
38
+ "body",
39
+ "caption",
40
+ "image",
41
+ "row",
42
+ "card",
43
+ "divider",
44
+ "button",
45
+ "field",
46
+ "checkbox",
47
+ ],
48
+ },
49
+ {
50
+ id: "heading",
51
+ component: "Text",
52
+ variant: "h1",
53
+ text: { path: "/title" },
54
+ },
55
+ {
56
+ id: "body",
57
+ component: "Text",
58
+ text: { path: "/body" },
59
+ },
60
+ {
61
+ id: "caption",
62
+ component: "Text",
63
+ variant: "caption",
64
+ text: "Fine print",
65
+ },
66
+ {
67
+ id: "image",
68
+ component: "Image",
69
+ url: { path: "/imageUrl" },
70
+ altText: "Preview",
71
+ },
72
+ {
73
+ id: "row",
74
+ component: "Row",
75
+ gap: 1,
76
+ align: "center",
77
+ justify: "between",
78
+ children: ["rowText"],
79
+ },
80
+ {
81
+ id: "rowText",
82
+ component: "Text",
83
+ text: "Inside row",
84
+ },
85
+ {
86
+ id: "card",
87
+ component: "Card",
88
+ title: "Details",
89
+ padding: 3,
90
+ },
91
+ { id: "divider", component: "Divider", flush: true },
92
+ {
93
+ id: "button",
94
+ component: "Button",
95
+ label: "Open",
96
+ action: {
97
+ name: "open",
98
+ context: {
99
+ ticketId: { path: "/ticketId" },
100
+ literal: "kept",
101
+ missing: { path: "/missing" },
102
+ },
103
+ },
104
+ },
105
+ {
106
+ id: "field",
107
+ component: "TextField",
108
+ label: "Email",
109
+ placeholder: "you@example.com",
110
+ text: { path: "/form/email" },
111
+ },
112
+ {
113
+ id: "checkbox",
114
+ component: "CheckBox",
115
+ label: "Accepted",
116
+ value: { path: "/form/accepted" },
117
+ },
118
+ ],
119
+ },
120
+ },
121
+ {
122
+ version: "v0.9",
123
+ updateDataModel: {
124
+ surfaceId: "main",
125
+ data: {
126
+ title: "Welcome",
127
+ body: "**Hello**",
128
+ imageUrl: "https://example.com/image.png",
129
+ ticketId: "ticket-1",
130
+ form: { email: "ada@example.com", accepted: true },
131
+ },
132
+ },
133
+ },
134
+ ]);
135
+ const surface = result.state.get("main");
136
+ expect(surface).toBeDefined();
137
+
138
+ const converted = convertSurfaceToUISpec(surface!);
139
+
140
+ expect(converted.warnings).toEqual([]);
141
+ expect(converted.spec).toEqual({
142
+ $type: "Col",
143
+ gap: 2,
144
+ children: [
145
+ { $type: "Header", text: "Welcome" },
146
+ { $type: "Markdown", value: "**Hello**" },
147
+ { $type: "Caption", value: "Fine print" },
148
+ {
149
+ $type: "Image",
150
+ src: "https://example.com/image.png",
151
+ alt: "Preview",
152
+ },
153
+ {
154
+ $type: "Row",
155
+ gap: 1,
156
+ align: "center",
157
+ justify: "between",
158
+ children: [{ $type: "Markdown", value: "Inside row" }],
159
+ },
160
+ { $type: "Card", title: "Details", padding: 3 },
161
+ { $type: "Divider", flush: true },
162
+ {
163
+ $type: "Button",
164
+ label: "Open",
165
+ $action: {
166
+ type: "a2ui:action",
167
+ name: "open",
168
+ surfaceId: "main",
169
+ sourceComponentId: "button",
170
+ context: { ticketId: "ticket-1", literal: "kept" },
171
+ },
172
+ },
173
+ {
174
+ $type: "Input",
175
+ label: "Email",
176
+ placeholder: "you@example.com",
177
+ name: "email",
178
+ },
179
+ {
180
+ $type: "Checkbox",
181
+ label: "Accepted",
182
+ name: "accepted",
183
+ defaultChecked: true,
184
+ },
185
+ ],
186
+ });
187
+ });
188
+
189
+ it("drops an unresolvable bound prop without throwing", () => {
190
+ const surface = surfaceFrom([
191
+ {
192
+ id: "root",
193
+ component: "Text",
194
+ text: { path: "/missing" },
195
+ },
196
+ ]);
197
+
198
+ expect(convertSurfaceToUISpec(surface)).toEqual({
199
+ spec: { $type: "Markdown" },
200
+ warnings: [],
201
+ });
202
+ });
203
+
204
+ it("expands template children relative to each bound item", () => {
205
+ const surface = surfaceFrom(
206
+ [
207
+ {
208
+ id: "root",
209
+ component: "Column",
210
+ children: {
211
+ template: { componentId: "item", path: "/items" },
212
+ },
213
+ },
214
+ {
215
+ id: "item",
216
+ component: "Text",
217
+ text: { path: "/name" },
218
+ },
219
+ ],
220
+ { items: [{ name: "one" }, { name: "two" }] },
221
+ );
222
+
223
+ expect(convertSurfaceToUISpec(surface)).toEqual({
224
+ spec: {
225
+ $type: "ListView",
226
+ children: [
227
+ {
228
+ $type: "ListViewItem",
229
+ children: { $type: "Markdown", value: "one" },
230
+ },
231
+ {
232
+ $type: "ListViewItem",
233
+ children: { $type: "Markdown", value: "two" },
234
+ },
235
+ ],
236
+ },
237
+ warnings: [],
238
+ });
239
+ });
240
+
241
+ it("caps template expansion at 100 items", () => {
242
+ const surface = surfaceFrom(
243
+ [
244
+ {
245
+ id: "root",
246
+ component: "Column",
247
+ children: {
248
+ template: { componentId: "item", path: "/items" },
249
+ },
250
+ },
251
+ {
252
+ id: "item",
253
+ component: "Text",
254
+ text: { path: "/" },
255
+ },
256
+ ],
257
+ { items: Array.from({ length: 101 }, (_, index) => `item-${index}`) },
258
+ );
259
+
260
+ const result = convertSurfaceToUISpec(surface);
261
+ expect((result.spec as UIElement).children).toHaveLength(100);
262
+ expect(result.warnings).toContain(
263
+ "A2UI template expansion was capped at 100 items.",
264
+ );
265
+ });
266
+
267
+ it("truncates a component cycle", () => {
268
+ const surface = surfaceFrom([
269
+ {
270
+ id: "root",
271
+ component: "Row",
272
+ children: ["root"],
273
+ },
274
+ ]);
275
+
276
+ expect(convertSurfaceToUISpec(surface)).toEqual({
277
+ spec: { $type: "Row" },
278
+ warnings: ['A2UI component cycle detected at "root".'],
279
+ });
280
+ });
281
+
282
+ it("truncates component resolution at depth 32", () => {
283
+ const components = Array.from({ length: 34 }, (_, index) => ({
284
+ id: index === 0 ? "root" : `node-${index}`,
285
+ component: "Row",
286
+ ...(index < 33
287
+ ? { children: [index === 0 ? "node-1" : `node-${index + 1}`] }
288
+ : {}),
289
+ }));
290
+ const result = convertSurfaceToUISpec(surfaceFrom(components));
291
+ let node = result.spec as UIElement;
292
+ let count = 1;
293
+ while (Array.isArray(node.children) && node.children.length > 0) {
294
+ node = node.children[0] as UIElement;
295
+ count++;
296
+ }
297
+
298
+ expect(count).toBe(32);
299
+ expect(result.warnings).toContain("A2UI depth cap of 32 was reached.");
300
+ });
301
+
302
+ it("enforces the total emitted node budget", () => {
303
+ const childCount = 5001;
304
+ const components = [
305
+ {
306
+ id: "root",
307
+ component: "Row",
308
+ children: Array.from(
309
+ { length: childCount },
310
+ (_, index) => `child-${index}`,
311
+ ),
312
+ },
313
+ ...Array.from({ length: childCount }, (_, index) => ({
314
+ id: `child-${index}`,
315
+ component: "Divider",
316
+ })),
317
+ ];
318
+ const result = convertSurfaceToUISpec(surfaceFrom(components));
319
+
320
+ expect((result.spec as UIElement).children).toHaveLength(4999);
321
+ expect(result.warnings).toContain("A2UI node budget of 5000 was reached.");
322
+ });
323
+
324
+ it("skips an unknown component with a warning naming it", () => {
325
+ const result = convertSurfaceToUISpec(
326
+ surfaceFrom([{ id: "root", component: "VideoPlayer" }]),
327
+ );
328
+
329
+ expect(result.spec).toBeNull();
330
+ expect(result.warnings).toEqual([
331
+ 'Unknown A2UI component "VideoPlayer" was skipped.',
332
+ ]);
333
+ });
334
+
335
+ it("returns null with a warning when root is missing", () => {
336
+ expect(
337
+ convertSurfaceToUISpec(
338
+ surfaceFrom([{ id: "other", component: "Divider" }]),
339
+ ),
340
+ ).toEqual({
341
+ spec: null,
342
+ warnings: ['A2UI root component "root" was not found.'],
343
+ });
344
+ });
345
+ });