@assistant-ui/react-generative-ui 0.0.20 → 0.0.21

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.
@@ -1 +1 @@
1
- {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/a2ui/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,iBAAc;AACnD,OAAO,EAEL,KAAK,gBAAgB,EAEtB,mBAAgB;AA8kBjB,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE;IAAE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD;IACD,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CA+BA"}
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/a2ui/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,iBAAc;AACnD,OAAO,EAEL,KAAK,gBAAgB,EAEtB,mBAAgB;AAynBjB,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE;IAAE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD;IACD,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CA+BA"}
@@ -97,11 +97,17 @@ const reserveNode = (context) => {
97
97
  context.emittedNodes++;
98
98
  return true;
99
99
  };
100
- const childrenOf = (node, dataSource, context, depth, visited) => {
100
+ const childReferences = (node) => {
101
101
  const children = node["children"];
102
- if (!Array.isArray(children)) return [];
102
+ const references = Array.isArray(children) ? [...children] : [];
103
+ if (node["child"] !== void 0) references.push(node["child"]);
104
+ if (node["component"] === "Modal") references.push(node["trigger"], node["content"]);
105
+ if (node["component"] === "Tabs" && Array.isArray(node["tabs"])) for (const tab of node["tabs"]) references.push(isRecord(tab) ? tab["child"] : void 0);
106
+ return references;
107
+ };
108
+ const childrenOf = (node, dataSource, context, depth, visited) => {
103
109
  const result = [];
104
- for (const childId of children) {
110
+ for (const childId of childReferences(node)) {
105
111
  if (typeof childId !== "string") {
106
112
  context.warnings.push(`Component "${String(node["id"] ?? "")}" has a malformed child reference.`);
107
113
  continue;
@@ -111,18 +117,26 @@ const childrenOf = (node, dataSource, context, depth, visited) => {
111
117
  }
112
118
  return result;
113
119
  };
114
- const mappedAction = (node, props, dataSource, context) => {
120
+ const textLabel = (node, children, context) => {
121
+ const references = childReferences(node);
122
+ const [reference] = references;
123
+ const [child] = children;
124
+ if (references.length !== 1 || children.length !== 1 || typeof reference !== "string" || !child || context.surface.components.get(reference)?.["component"] !== "Text") return;
125
+ const text = child.$type === "Header" ? child["text"] : child["value"];
126
+ return typeof text === "string" ? text : void 0;
127
+ };
128
+ const mappedAction = (node, props, context) => {
115
129
  const action = props["action"];
116
- const actionName = typeof action === "string" ? action : isRecord(action) && typeof action["name"] === "string" ? action["name"] : void 0;
130
+ const event = isRecord(action) && isRecord(action["event"]) ? action["event"] : action;
131
+ const actionName = typeof event === "string" ? event : isRecord(event) && typeof event["name"] === "string" ? event["name"] : void 0;
117
132
  if (!actionName) return void 0;
118
- const rawContext = isRecord(action) ? action["context"] : void 0;
119
- const resolvedContext = rawContext === void 0 ? void 0 : materialize(rawContext, dataSource);
133
+ const actionContext = isRecord(event) ? event["context"] : void 0;
120
134
  return {
121
135
  type: "a2ui:action",
122
136
  name: actionName,
123
137
  surfaceId: context.surfaceId,
124
138
  sourceComponentId: typeof node["id"] === "string" ? node["id"] : "",
125
- ...resolvedContext !== void 0 ? { context: resolvedContext } : {}
139
+ ...actionContext !== void 0 ? { context: actionContext } : {}
126
140
  };
127
141
  };
128
142
  const choiceOptions = (value) => {
@@ -134,7 +148,7 @@ const choiceOptions = (value) => {
134
148
  });
135
149
  return options;
136
150
  };
137
- const mappedProps = (node, props, dataSource, context) => {
151
+ const mappedProps = (node, props, context) => {
138
152
  const component = node["component"];
139
153
  if (component === "Text") {
140
154
  const text = stringProp(props, ["text", "value"]);
@@ -228,7 +242,7 @@ const mappedProps = (node, props, dataSource, context) => {
228
242
  const buttonStyle = props["buttonStyle"];
229
243
  const block = props["block"];
230
244
  const submit = props["submit"];
231
- const action = mappedAction(node, props, dataSource, context);
245
+ const action = mappedAction(node, props, context);
232
246
  return {
233
247
  $type: "Button",
234
248
  ...label !== void 0 ? { label } : {},
@@ -364,11 +378,11 @@ function convertComponent(componentId, dataSource, context, depth, visited) {
364
378
  }
365
379
  const props = {};
366
380
  for (const [key, value] of Object.entries(node)) {
367
- if (key === "id" || key === "component" || key === "children") continue;
381
+ if (key === "id" || key === "component" || key === "children" || key === "child") continue;
368
382
  const resolved = materialize(value, dataSource);
369
383
  if (resolved !== void 0) setOwnProperty(props, key, resolved);
370
384
  }
371
- const mapped = mappedProps(node, props, dataSource, context);
385
+ const mapped = mappedProps(node, props, context);
372
386
  if (!mapped && SUPPORTED_COMPONENTS.has(component)) {
373
387
  context.warnings.push(`A2UI component "${component}" could not be mapped and was skipped.`);
374
388
  return null;
@@ -382,6 +396,13 @@ function convertComponent(componentId, dataSource, context, depth, visited) {
382
396
  const converted = mapped ?? retained;
383
397
  if (!converted) return null;
384
398
  const children = childrenOf(node, dataSource, context, depth, visited);
399
+ if (mapped?.$type === "Button" && mapped["label"] === void 0) {
400
+ const label = textLabel(node, children, context);
401
+ if (label !== void 0) return {
402
+ ...mapped,
403
+ label
404
+ };
405
+ }
385
406
  const listChildren = component === "List" && mapped?.$type === "ListView" ? children.map((child) => ({
386
407
  $type: "ListViewItem",
387
408
  children: child
@@ -1 +1 @@
1
- {"version":3,"file":"convert.js","names":[],"sources":["../../src/a2ui/convert.ts"],"sourcesContent":["import { ICON_NAMES, type UIElement } from \"../ir\";\nimport {\n A2UI_SURFACE_ID,\n type A2uiSurfaceState,\n type A2uiTemplateChildren,\n} from \"./types\";\n\nconst DEPTH_CAP = 32;\nconst TEMPLATE_ITEM_CAP = 100;\nconst NODE_BUDGET = 5000;\n\nconst SUPPORTED_COMPONENTS = new Set([\n \"Text\",\n \"Image\",\n \"Icon\",\n \"Row\",\n \"Column\",\n \"List\",\n \"Card\",\n \"Divider\",\n \"Button\",\n \"TextField\",\n \"CheckBox\",\n \"ChoicePicker\",\n \"DateTimeInput\",\n]);\n\nconst ICON_NAME_SET: ReadonlySet<string> = new Set(ICON_NAMES);\nconst ICON_SIZE_SET: ReadonlySet<string> = new Set([\"sm\", \"md\", \"lg\"]);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (!isRecord(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n\nconst setOwnProperty = (\n target: Record<string, unknown>,\n key: string,\n value: unknown,\n) => {\n if (key === \"__proto__\") {\n Object.defineProperty(target, key, {\n value,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n } else {\n target[key] = value;\n }\n};\n\nconst isBinding = (value: unknown): value is { readonly path: string } =>\n isPlainObject(value) &&\n Object.keys(value).length === 1 &&\n typeof value[\"path\"] === \"string\";\n\nconst isTemplateChildren = (value: unknown): value is A2uiTemplateChildren =>\n isPlainObject(value) &&\n Object.keys(value).length === 1 &&\n isPlainObject(value[\"template\"]) &&\n Object.keys(value[\"template\"]).length === 2 &&\n typeof value[\"template\"][\"componentId\"] === \"string\" &&\n typeof value[\"template\"][\"path\"] === \"string\";\n\nconst decodePointer = (path: string): string[] | undefined => {\n if (path === \"\" || path === \"/\") return [];\n if (!path.startsWith(\"/\")) return undefined;\n return path\n .slice(1)\n .split(\"/\")\n .map((segment) => segment.replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\"));\n};\n\nconst resolvePointer = (source: unknown, path: string): unknown => {\n const segments = decodePointer(path);\n if (!segments) return undefined;\n let current = source;\n for (const segment of segments) {\n if (Array.isArray(current)) {\n if (!/^(0|[1-9]\\d*)$/.test(segment)) return undefined;\n current = current[Number(segment)];\n continue;\n }\n if (!isRecord(current) || !Object.hasOwn(current, segment)) {\n return undefined;\n }\n current = current[segment];\n }\n return current;\n};\n\nconst bindingPath = (value: unknown): string | undefined =>\n isBinding(value) ? value.path : undefined;\n\nconst lastPointerSegment = (path: string | undefined): string | undefined => {\n if (!path) return undefined;\n const segments = decodePointer(path);\n return segments?.at(-1);\n};\n\nconst materialize = (value: unknown, source: unknown): unknown => {\n if (isBinding(value)) return resolvePointer(source, value.path);\n if (Array.isArray(value)) {\n return value\n .map((entry) => materialize(entry, source))\n .filter((entry) => entry !== undefined);\n }\n if (!isPlainObject(value)) return value;\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n const resolved = materialize(entry, source);\n if (resolved !== undefined) {\n setOwnProperty(result, key, resolved);\n }\n }\n return result;\n};\n\nconst firstDefined = (\n props: Record<string, unknown>,\n keys: readonly string[],\n): unknown => {\n for (const key of keys) {\n if (props[key] !== undefined) return props[key];\n }\n return undefined;\n};\n\nconst stringProp = (\n props: Record<string, unknown>,\n keys: readonly string[],\n): string | undefined => {\n const value = firstDefined(props, keys);\n return typeof value === \"string\" ? value : undefined;\n};\n\nconst sourceSurfaceId = (surface: A2uiSurfaceState): string =>\n (surface as A2uiSurfaceState & { [A2UI_SURFACE_ID]?: string })[\n A2UI_SURFACE_ID\n ] ?? \"\";\n\ntype ConversionContext = {\n readonly surface: A2uiSurfaceState;\n readonly surfaceId: string;\n readonly warnings: string[];\n emittedNodes: number;\n depthWarned: boolean;\n budgetWarned: boolean;\n templateCapWarned: boolean;\n readonly keepUnknownComponents: boolean;\n};\n\nconst reserveNode = (context: ConversionContext): boolean => {\n if (context.emittedNodes >= NODE_BUDGET) {\n if (!context.budgetWarned) {\n context.warnings.push(`A2UI node budget of ${NODE_BUDGET} was reached.`);\n context.budgetWarned = true;\n }\n return false;\n }\n context.emittedNodes++;\n return true;\n};\n\nconst childrenOf = (\n node: Record<string, unknown>,\n dataSource: unknown,\n context: ConversionContext,\n depth: number,\n visited: Set<string>,\n): UIElement[] => {\n const children = node[\"children\"];\n if (!Array.isArray(children)) return [];\n const result: UIElement[] = [];\n for (const childId of children) {\n if (typeof childId !== \"string\") {\n context.warnings.push(\n `Component \"${String(node[\"id\"] ?? \"\")}\" has a malformed child reference.`,\n );\n continue;\n }\n const child = convertComponent(\n childId,\n dataSource,\n context,\n depth + 1,\n visited,\n );\n if (child) result.push(child);\n }\n return result;\n};\n\nconst mappedAction = (\n node: Record<string, unknown>,\n props: Record<string, unknown>,\n dataSource: unknown,\n context: ConversionContext,\n): UIElement[\"$action\"] | undefined => {\n const action = props[\"action\"];\n const actionName =\n typeof action === \"string\"\n ? action\n : isRecord(action) && typeof action[\"name\"] === \"string\"\n ? action[\"name\"]\n : undefined;\n if (!actionName) return undefined;\n const rawContext = isRecord(action) ? action[\"context\"] : undefined;\n const resolvedContext =\n rawContext === undefined ? undefined : materialize(rawContext, dataSource);\n return {\n type: \"a2ui:action\",\n name: actionName,\n surfaceId: context.surfaceId,\n sourceComponentId: typeof node[\"id\"] === \"string\" ? node[\"id\"] : \"\",\n ...(resolvedContext !== undefined ? { context: resolvedContext } : {}),\n };\n};\n\nconst choiceOptions = (value: unknown): { label: string; value: string }[] => {\n if (!Array.isArray(value)) return [];\n const options: { label: string; value: string }[] = [];\n for (const option of value) {\n if (\n isRecord(option) &&\n typeof option[\"label\"] === \"string\" &&\n typeof option[\"value\"] === \"string\"\n ) {\n options.push({ label: option[\"label\"], value: option[\"value\"] });\n }\n }\n return options;\n};\n\nconst mappedProps = (\n node: Record<string, unknown>,\n props: Record<string, unknown>,\n dataSource: unknown,\n context: ConversionContext,\n): UIElement | undefined => {\n const component = node[\"component\"];\n\n if (component === \"Text\") {\n const text = stringProp(props, [\"text\", \"value\"]);\n const variant = props[\"variant\"];\n if (typeof variant === \"string\" && /^h[1-6]$/.test(variant)) {\n return {\n $type: \"Header\",\n ...(text !== undefined ? { text } : {}),\n };\n }\n if (variant === \"caption\") {\n return {\n $type: \"Caption\",\n ...(text !== undefined ? { value: text } : {}),\n };\n }\n return {\n $type: \"Markdown\",\n ...(text !== undefined ? { value: text } : {}),\n };\n }\n\n if (component === \"Image\") {\n const src = stringProp(props, [\"src\", \"url\"]);\n const alt = stringProp(props, [\"alt\", \"altText\", \"description\"]);\n const size = props[\"size\"];\n const round = props[\"round\"];\n return {\n $type: \"Image\",\n ...(src !== undefined ? { src } : {}),\n ...(alt !== undefined ? { alt } : {}),\n ...(typeof size === \"string\" || typeof size === \"number\" ? { size } : {}),\n ...(typeof round === \"boolean\" ? { round } : {}),\n };\n }\n\n if (component === \"Icon\") {\n const name = stringProp(props, [\"name\"]);\n if (!name || !ICON_NAME_SET.has(name)) return undefined;\n const size = props[\"size\"];\n return {\n $type: \"Icon\",\n name,\n ...(typeof size === \"string\" && ICON_SIZE_SET.has(size) ? { size } : {}),\n };\n }\n\n if (component === \"Row\") {\n const gap = props[\"gap\"];\n const align = firstDefined(props, [\"align\", \"alignment\"]);\n const justify = firstDefined(props, [\"justify\", \"distribution\"]);\n return {\n $type: \"Row\",\n ...(typeof gap === \"number\" ? { gap } : {}),\n ...(typeof align === \"string\" ? { align } : {}),\n ...(typeof justify === \"string\" ? { justify } : {}),\n };\n }\n\n if (component === \"Column\") {\n const gap = props[\"gap\"];\n const align = firstDefined(props, [\"align\", \"alignment\"]);\n return {\n $type: \"Col\",\n ...(typeof gap === \"number\" ? { gap } : {}),\n ...(typeof align === \"string\" ? { align } : {}),\n };\n }\n\n if (component === \"List\") {\n const direction = props[\"direction\"];\n const align = props[\"align\"];\n if (direction === \"horizontal\") {\n return {\n $type: \"Row\",\n ...(typeof align === \"string\" ? { align } : {}),\n };\n }\n return { $type: \"ListView\" };\n }\n\n if (component === \"Card\") {\n const title = props[\"title\"];\n const padding = props[\"padding\"];\n const background = props[\"background\"];\n return {\n $type: \"Card\",\n ...(typeof title === \"string\" ? { title } : {}),\n ...(typeof padding === \"number\" ? { padding } : {}),\n ...(typeof background === \"string\" ? { background } : {}),\n };\n }\n\n if (component === \"Divider\") {\n return {\n $type: \"Divider\",\n ...(typeof props[\"flush\"] === \"boolean\" ? { flush: props[\"flush\"] } : {}),\n };\n }\n\n if (component === \"Button\") {\n const label = stringProp(props, [\"label\", \"text\"]);\n const buttonStyle = props[\"buttonStyle\"];\n const block = props[\"block\"];\n const submit = props[\"submit\"];\n const action = mappedAction(node, props, dataSource, context);\n return {\n $type: \"Button\",\n ...(label !== undefined ? { label } : {}),\n ...(typeof buttonStyle === \"string\" ? { buttonStyle } : {}),\n ...(typeof block === \"boolean\" ? { block } : {}),\n ...(typeof submit === \"boolean\" ? { submit } : {}),\n ...(action ? { $action: action } : {}),\n };\n }\n\n const binding = firstDefined(node, [\"text\", \"value\", \"binding\"]);\n const name = lastPointerSegment(bindingPath(binding));\n const label = stringProp(props, [\"label\"]);\n\n if (component === \"TextField\") {\n const placeholder = stringProp(props, [\"placeholder\"]);\n const multiline =\n typeof props[\"multiline\"] === \"boolean\"\n ? props[\"multiline\"]\n : props[\"textFieldType\"] === \"longText\"\n ? true\n : undefined;\n return {\n $type: \"Input\",\n ...(placeholder !== undefined ? { placeholder } : {}),\n ...(multiline !== undefined ? { multiline } : {}),\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n };\n }\n\n if (component === \"CheckBox\") {\n const defaultChecked = firstDefined(props, [\"defaultChecked\", \"value\"]);\n return {\n $type: \"Checkbox\",\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(typeof defaultChecked === \"boolean\" ? { defaultChecked } : {}),\n };\n }\n\n if (component === \"ChoicePicker\") {\n const options = choiceOptions(props[\"options\"]);\n const value = props[\"value\"];\n const defaultValue =\n typeof value === \"string\"\n ? value\n : Array.isArray(value) && typeof value[0] === \"string\"\n ? value[0]\n : undefined;\n const radioStyle =\n props[\"variant\"] === \"radio\" ||\n props[\"variant\"] === \"single\" ||\n props[\"variant\"] === \"singleSelection\" ||\n props[\"displayStyle\"] === \"radio\" ||\n (props[\"variant\"] === \"mutuallyExclusive\" &&\n props[\"displayStyle\"] !== \"chips\");\n if (radioStyle) {\n return {\n $type: \"RadioGroup\",\n options,\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(defaultValue !== undefined ? { defaultValue } : {}),\n };\n }\n const placeholder = stringProp(props, [\"placeholder\"]);\n return {\n $type: \"Select\",\n options,\n ...(placeholder !== undefined ? { placeholder } : {}),\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n };\n }\n\n if (component === \"DateTimeInput\") {\n const value = stringProp(props, [\"value\"]);\n const min = stringProp(props, [\"min\"]);\n const max = stringProp(props, [\"max\"]);\n return {\n $type: \"DatePicker\",\n ...(value !== undefined ? { value } : {}),\n ...(min !== undefined ? { min } : {}),\n ...(max !== undefined ? { max } : {}),\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n };\n }\n\n return undefined;\n};\n\nconst convertTemplate = (\n node: Record<string, unknown>,\n templateChildren: A2uiTemplateChildren,\n dataSource: unknown,\n context: ConversionContext,\n depth: number,\n visited: Set<string>,\n retained?: UIElement,\n mappedContainer?: UIElement,\n): UIElement | null => {\n if (!reserveNode(context)) return null;\n const horizontalList =\n node[\"component\"] === \"List\" &&\n materialize(node[\"direction\"], dataSource) === \"horizontal\";\n const container = mappedContainer ??\n retained ?? {\n $type: horizontalList ? \"Row\" : \"ListView\",\n };\n const list = resolvePointer(dataSource, templateChildren.template.path);\n if (!Array.isArray(list)) {\n context.warnings.push(\n `Template on component \"${String(node[\"id\"] ?? \"\")}\" did not resolve to a list.`,\n );\n return { ...container, children: [] };\n }\n const itemCount = Math.min(list.length, TEMPLATE_ITEM_CAP);\n if (list.length > TEMPLATE_ITEM_CAP && !context.templateCapWarned) {\n context.warnings.push(\n `A2UI template expansion was capped at ${TEMPLATE_ITEM_CAP} items.`,\n );\n context.templateCapWarned = true;\n }\n const children: UIElement[] = [];\n for (let index = 0; index < itemCount; index++) {\n if (!retained && !horizontalList && !reserveNode(context)) break;\n const child = convertComponent(\n templateChildren.template.componentId,\n list[index],\n context,\n depth + 1,\n visited,\n );\n if (retained || horizontalList) {\n if (child) children.push(child);\n } else {\n children.push({\n $type: \"ListViewItem\",\n ...(child ? { children: child } : {}),\n });\n }\n }\n return { ...container, children };\n};\n\nfunction convertComponent(\n componentId: string,\n dataSource: unknown,\n context: ConversionContext,\n depth: number,\n visited: Set<string>,\n): UIElement | null {\n if (depth >= DEPTH_CAP) {\n if (!context.depthWarned) {\n context.warnings.push(`A2UI depth cap of ${DEPTH_CAP} was reached.`);\n context.depthWarned = true;\n }\n return null;\n }\n if (visited.has(componentId)) {\n context.warnings.push(`A2UI component cycle detected at \"${componentId}\".`);\n return null;\n }\n const node = context.surface.components.get(componentId);\n if (!node) {\n context.warnings.push(`A2UI component \"${componentId}\" was not found.`);\n return null;\n }\n const component = node[\"component\"];\n\n visited.add(componentId);\n try {\n if (typeof component !== \"string\") {\n context.warnings.push(\n `Unknown A2UI component \"${String(component ?? \"\")}\" was skipped.`,\n );\n return null;\n }\n const templateChildren = node[\"children\"];\n const hasTemplate = isTemplateChildren(templateChildren);\n if (\n !SUPPORTED_COMPONENTS.has(component) &&\n !context.keepUnknownComponents &&\n !hasTemplate\n ) {\n context.warnings.push(\n `Unknown A2UI component \"${component}\" was skipped.`,\n );\n return null;\n }\n const props: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(node)) {\n if (key === \"id\" || key === \"component\" || key === \"children\") continue;\n const resolved = materialize(value, dataSource);\n if (resolved !== undefined) setOwnProperty(props, key, resolved);\n }\n const mapped = mappedProps(node, props, dataSource, context);\n if (!mapped && SUPPORTED_COMPONENTS.has(component)) {\n context.warnings.push(\n `A2UI component \"${component}\" could not be mapped and was skipped.`,\n );\n return null;\n }\n const retained =\n !mapped && context.keepUnknownComponents\n ? {\n $type: component,\n ...Object.fromEntries(\n Object.entries(props).filter(([key]) => !key.startsWith(\"$\")),\n ),\n }\n : undefined;\n if (hasTemplate) {\n return convertTemplate(\n node,\n templateChildren,\n dataSource,\n context,\n depth,\n visited,\n retained,\n component === \"List\" ? mapped : undefined,\n );\n }\n if (!reserveNode(context)) return null;\n const converted = mapped ?? retained;\n if (!converted) return null;\n const children = childrenOf(node, dataSource, context, depth, visited);\n const listChildren =\n component === \"List\" && mapped?.$type === \"ListView\"\n ? children.map((child) => ({ $type: \"ListViewItem\", children: child }))\n : children;\n return {\n ...converted,\n ...(listChildren.length > 0 ? { children: listChildren } : {}),\n };\n } finally {\n visited.delete(componentId);\n }\n}\n\nexport function convertSurfaceToUISpec(\n surface: A2uiSurfaceState,\n options: { readonly keepUnknownComponents?: boolean } = {},\n): {\n spec: UIElement | null;\n warnings: string[];\n} {\n const warnings: string[] = [];\n if (!surface.components.has(\"root\")) {\n return {\n spec: null,\n warnings: ['A2UI root component \"root\" was not found.'],\n };\n }\n const context: ConversionContext = {\n surface,\n surfaceId: sourceSurfaceId(surface),\n warnings,\n emittedNodes: 0,\n depthWarned: false,\n budgetWarned: false,\n templateCapWarned: false,\n keepUnknownComponents: options.keepUnknownComponents === true,\n };\n try {\n const spec = convertComponent(\n \"root\",\n surface.dataModel,\n context,\n 0,\n new Set(),\n );\n return { spec, warnings };\n } catch {\n warnings.push(\"A2UI surface conversion encountered malformed input.\");\n return { spec: null, warnings };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"convert.js","names":[],"sources":["../../src/a2ui/convert.ts"],"sourcesContent":["import { ICON_NAMES, type UIElement } from \"../ir\";\nimport {\n A2UI_SURFACE_ID,\n type A2uiSurfaceState,\n type A2uiTemplateChildren,\n} from \"./types\";\n\nconst DEPTH_CAP = 32;\nconst TEMPLATE_ITEM_CAP = 100;\nconst NODE_BUDGET = 5000;\n\nconst SUPPORTED_COMPONENTS = new Set([\n \"Text\",\n \"Image\",\n \"Icon\",\n \"Row\",\n \"Column\",\n \"List\",\n \"Card\",\n \"Divider\",\n \"Button\",\n \"TextField\",\n \"CheckBox\",\n \"ChoicePicker\",\n \"DateTimeInput\",\n]);\n\nconst ICON_NAME_SET: ReadonlySet<string> = new Set(ICON_NAMES);\nconst ICON_SIZE_SET: ReadonlySet<string> = new Set([\"sm\", \"md\", \"lg\"]);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (!isRecord(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n\nconst setOwnProperty = (\n target: Record<string, unknown>,\n key: string,\n value: unknown,\n) => {\n if (key === \"__proto__\") {\n Object.defineProperty(target, key, {\n value,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n } else {\n target[key] = value;\n }\n};\n\nconst isBinding = (value: unknown): value is { readonly path: string } =>\n isPlainObject(value) &&\n Object.keys(value).length === 1 &&\n typeof value[\"path\"] === \"string\";\n\nconst isTemplateChildren = (value: unknown): value is A2uiTemplateChildren =>\n isPlainObject(value) &&\n Object.keys(value).length === 1 &&\n isPlainObject(value[\"template\"]) &&\n Object.keys(value[\"template\"]).length === 2 &&\n typeof value[\"template\"][\"componentId\"] === \"string\" &&\n typeof value[\"template\"][\"path\"] === \"string\";\n\nconst decodePointer = (path: string): string[] | undefined => {\n if (path === \"\" || path === \"/\") return [];\n if (!path.startsWith(\"/\")) return undefined;\n return path\n .slice(1)\n .split(\"/\")\n .map((segment) => segment.replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\"));\n};\n\nconst resolvePointer = (source: unknown, path: string): unknown => {\n const segments = decodePointer(path);\n if (!segments) return undefined;\n let current = source;\n for (const segment of segments) {\n if (Array.isArray(current)) {\n if (!/^(0|[1-9]\\d*)$/.test(segment)) return undefined;\n current = current[Number(segment)];\n continue;\n }\n if (!isRecord(current) || !Object.hasOwn(current, segment)) {\n return undefined;\n }\n current = current[segment];\n }\n return current;\n};\n\nconst bindingPath = (value: unknown): string | undefined =>\n isBinding(value) ? value.path : undefined;\n\nconst lastPointerSegment = (path: string | undefined): string | undefined => {\n if (!path) return undefined;\n const segments = decodePointer(path);\n return segments?.at(-1);\n};\n\nconst materialize = (value: unknown, source: unknown): unknown => {\n if (isBinding(value)) return resolvePointer(source, value.path);\n if (Array.isArray(value)) {\n return value\n .map((entry) => materialize(entry, source))\n .filter((entry) => entry !== undefined);\n }\n if (!isPlainObject(value)) return value;\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n const resolved = materialize(entry, source);\n if (resolved !== undefined) {\n setOwnProperty(result, key, resolved);\n }\n }\n return result;\n};\n\nconst firstDefined = (\n props: Record<string, unknown>,\n keys: readonly string[],\n): unknown => {\n for (const key of keys) {\n if (props[key] !== undefined) return props[key];\n }\n return undefined;\n};\n\nconst stringProp = (\n props: Record<string, unknown>,\n keys: readonly string[],\n): string | undefined => {\n const value = firstDefined(props, keys);\n return typeof value === \"string\" ? value : undefined;\n};\n\nconst sourceSurfaceId = (surface: A2uiSurfaceState): string =>\n (surface as A2uiSurfaceState & { [A2UI_SURFACE_ID]?: string })[\n A2UI_SURFACE_ID\n ] ?? \"\";\n\ntype ConversionContext = {\n readonly surface: A2uiSurfaceState;\n readonly surfaceId: string;\n readonly warnings: string[];\n emittedNodes: number;\n depthWarned: boolean;\n budgetWarned: boolean;\n templateCapWarned: boolean;\n readonly keepUnknownComponents: boolean;\n};\n\nconst reserveNode = (context: ConversionContext): boolean => {\n if (context.emittedNodes >= NODE_BUDGET) {\n if (!context.budgetWarned) {\n context.warnings.push(`A2UI node budget of ${NODE_BUDGET} was reached.`);\n context.budgetWarned = true;\n }\n return false;\n }\n context.emittedNodes++;\n return true;\n};\n\nconst childReferences = (node: Record<string, unknown>): unknown[] => {\n const children = node[\"children\"];\n const references: unknown[] = Array.isArray(children) ? [...children] : [];\n if (node[\"child\"] !== undefined) references.push(node[\"child\"]);\n if (node[\"component\"] === \"Modal\") {\n references.push(node[\"trigger\"], node[\"content\"]);\n }\n if (node[\"component\"] === \"Tabs\" && Array.isArray(node[\"tabs\"])) {\n for (const tab of node[\"tabs\"]) {\n references.push(isRecord(tab) ? tab[\"child\"] : undefined);\n }\n }\n return references;\n};\n\nconst childrenOf = (\n node: Record<string, unknown>,\n dataSource: unknown,\n context: ConversionContext,\n depth: number,\n visited: Set<string>,\n): UIElement[] => {\n const result: UIElement[] = [];\n for (const childId of childReferences(node)) {\n if (typeof childId !== \"string\") {\n context.warnings.push(\n `Component \"${String(node[\"id\"] ?? \"\")}\" has a malformed child reference.`,\n );\n continue;\n }\n const child = convertComponent(\n childId,\n dataSource,\n context,\n depth + 1,\n visited,\n );\n if (child) result.push(child);\n }\n return result;\n};\n\nconst textLabel = (\n node: Record<string, unknown>,\n children: readonly UIElement[],\n context: ConversionContext,\n): string | undefined => {\n const references = childReferences(node);\n const [reference] = references;\n const [child] = children;\n if (\n references.length !== 1 ||\n children.length !== 1 ||\n typeof reference !== \"string\" ||\n !child ||\n context.surface.components.get(reference)?.[\"component\"] !== \"Text\"\n ) {\n return undefined;\n }\n const text = child.$type === \"Header\" ? child[\"text\"] : child[\"value\"];\n return typeof text === \"string\" ? text : undefined;\n};\n\nconst mappedAction = (\n node: Record<string, unknown>,\n props: Record<string, unknown>,\n context: ConversionContext,\n): UIElement[\"$action\"] | undefined => {\n const action = props[\"action\"];\n const event =\n isRecord(action) && isRecord(action[\"event\"]) ? action[\"event\"] : action;\n const actionName =\n typeof event === \"string\"\n ? event\n : isRecord(event) && typeof event[\"name\"] === \"string\"\n ? event[\"name\"]\n : undefined;\n if (!actionName) return undefined;\n const actionContext = isRecord(event) ? event[\"context\"] : undefined;\n return {\n type: \"a2ui:action\",\n name: actionName,\n surfaceId: context.surfaceId,\n sourceComponentId: typeof node[\"id\"] === \"string\" ? node[\"id\"] : \"\",\n ...(actionContext !== undefined ? { context: actionContext } : {}),\n };\n};\n\nconst choiceOptions = (value: unknown): { label: string; value: string }[] => {\n if (!Array.isArray(value)) return [];\n const options: { label: string; value: string }[] = [];\n for (const option of value) {\n if (\n isRecord(option) &&\n typeof option[\"label\"] === \"string\" &&\n typeof option[\"value\"] === \"string\"\n ) {\n options.push({ label: option[\"label\"], value: option[\"value\"] });\n }\n }\n return options;\n};\n\nconst mappedProps = (\n node: Record<string, unknown>,\n props: Record<string, unknown>,\n context: ConversionContext,\n): UIElement | undefined => {\n const component = node[\"component\"];\n\n if (component === \"Text\") {\n const text = stringProp(props, [\"text\", \"value\"]);\n const variant = props[\"variant\"];\n if (typeof variant === \"string\" && /^h[1-6]$/.test(variant)) {\n return {\n $type: \"Header\",\n ...(text !== undefined ? { text } : {}),\n };\n }\n if (variant === \"caption\") {\n return {\n $type: \"Caption\",\n ...(text !== undefined ? { value: text } : {}),\n };\n }\n return {\n $type: \"Markdown\",\n ...(text !== undefined ? { value: text } : {}),\n };\n }\n\n if (component === \"Image\") {\n const src = stringProp(props, [\"src\", \"url\"]);\n const alt = stringProp(props, [\"alt\", \"altText\", \"description\"]);\n const size = props[\"size\"];\n const round = props[\"round\"];\n return {\n $type: \"Image\",\n ...(src !== undefined ? { src } : {}),\n ...(alt !== undefined ? { alt } : {}),\n ...(typeof size === \"string\" || typeof size === \"number\" ? { size } : {}),\n ...(typeof round === \"boolean\" ? { round } : {}),\n };\n }\n\n if (component === \"Icon\") {\n const name = stringProp(props, [\"name\"]);\n if (!name || !ICON_NAME_SET.has(name)) return undefined;\n const size = props[\"size\"];\n return {\n $type: \"Icon\",\n name,\n ...(typeof size === \"string\" && ICON_SIZE_SET.has(size) ? { size } : {}),\n };\n }\n\n if (component === \"Row\") {\n const gap = props[\"gap\"];\n const align = firstDefined(props, [\"align\", \"alignment\"]);\n const justify = firstDefined(props, [\"justify\", \"distribution\"]);\n return {\n $type: \"Row\",\n ...(typeof gap === \"number\" ? { gap } : {}),\n ...(typeof align === \"string\" ? { align } : {}),\n ...(typeof justify === \"string\" ? { justify } : {}),\n };\n }\n\n if (component === \"Column\") {\n const gap = props[\"gap\"];\n const align = firstDefined(props, [\"align\", \"alignment\"]);\n return {\n $type: \"Col\",\n ...(typeof gap === \"number\" ? { gap } : {}),\n ...(typeof align === \"string\" ? { align } : {}),\n };\n }\n\n if (component === \"List\") {\n const direction = props[\"direction\"];\n const align = props[\"align\"];\n if (direction === \"horizontal\") {\n return {\n $type: \"Row\",\n ...(typeof align === \"string\" ? { align } : {}),\n };\n }\n return { $type: \"ListView\" };\n }\n\n if (component === \"Card\") {\n const title = props[\"title\"];\n const padding = props[\"padding\"];\n const background = props[\"background\"];\n return {\n $type: \"Card\",\n ...(typeof title === \"string\" ? { title } : {}),\n ...(typeof padding === \"number\" ? { padding } : {}),\n ...(typeof background === \"string\" ? { background } : {}),\n };\n }\n\n if (component === \"Divider\") {\n return {\n $type: \"Divider\",\n ...(typeof props[\"flush\"] === \"boolean\" ? { flush: props[\"flush\"] } : {}),\n };\n }\n\n if (component === \"Button\") {\n const label = stringProp(props, [\"label\", \"text\"]);\n const buttonStyle = props[\"buttonStyle\"];\n const block = props[\"block\"];\n const submit = props[\"submit\"];\n const action = mappedAction(node, props, context);\n return {\n $type: \"Button\",\n ...(label !== undefined ? { label } : {}),\n ...(typeof buttonStyle === \"string\" ? { buttonStyle } : {}),\n ...(typeof block === \"boolean\" ? { block } : {}),\n ...(typeof submit === \"boolean\" ? { submit } : {}),\n ...(action ? { $action: action } : {}),\n };\n }\n\n const binding = firstDefined(node, [\"text\", \"value\", \"binding\"]);\n const name = lastPointerSegment(bindingPath(binding));\n const label = stringProp(props, [\"label\"]);\n\n if (component === \"TextField\") {\n const placeholder = stringProp(props, [\"placeholder\"]);\n const multiline =\n typeof props[\"multiline\"] === \"boolean\"\n ? props[\"multiline\"]\n : props[\"textFieldType\"] === \"longText\"\n ? true\n : undefined;\n return {\n $type: \"Input\",\n ...(placeholder !== undefined ? { placeholder } : {}),\n ...(multiline !== undefined ? { multiline } : {}),\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n };\n }\n\n if (component === \"CheckBox\") {\n const defaultChecked = firstDefined(props, [\"defaultChecked\", \"value\"]);\n return {\n $type: \"Checkbox\",\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(typeof defaultChecked === \"boolean\" ? { defaultChecked } : {}),\n };\n }\n\n if (component === \"ChoicePicker\") {\n const options = choiceOptions(props[\"options\"]);\n const value = props[\"value\"];\n const defaultValue =\n typeof value === \"string\"\n ? value\n : Array.isArray(value) && typeof value[0] === \"string\"\n ? value[0]\n : undefined;\n const radioStyle =\n props[\"variant\"] === \"radio\" ||\n props[\"variant\"] === \"single\" ||\n props[\"variant\"] === \"singleSelection\" ||\n props[\"displayStyle\"] === \"radio\" ||\n (props[\"variant\"] === \"mutuallyExclusive\" &&\n props[\"displayStyle\"] !== \"chips\");\n if (radioStyle) {\n return {\n $type: \"RadioGroup\",\n options,\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(defaultValue !== undefined ? { defaultValue } : {}),\n };\n }\n const placeholder = stringProp(props, [\"placeholder\"]);\n return {\n $type: \"Select\",\n options,\n ...(placeholder !== undefined ? { placeholder } : {}),\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n };\n }\n\n if (component === \"DateTimeInput\") {\n const value = stringProp(props, [\"value\"]);\n const min = stringProp(props, [\"min\"]);\n const max = stringProp(props, [\"max\"]);\n return {\n $type: \"DatePicker\",\n ...(value !== undefined ? { value } : {}),\n ...(min !== undefined ? { min } : {}),\n ...(max !== undefined ? { max } : {}),\n ...(label !== undefined ? { label } : {}),\n ...(name !== undefined ? { name } : {}),\n };\n }\n\n return undefined;\n};\n\nconst convertTemplate = (\n node: Record<string, unknown>,\n templateChildren: A2uiTemplateChildren,\n dataSource: unknown,\n context: ConversionContext,\n depth: number,\n visited: Set<string>,\n retained?: UIElement,\n mappedContainer?: UIElement,\n): UIElement | null => {\n if (!reserveNode(context)) return null;\n const horizontalList =\n node[\"component\"] === \"List\" &&\n materialize(node[\"direction\"], dataSource) === \"horizontal\";\n const container = mappedContainer ??\n retained ?? {\n $type: horizontalList ? \"Row\" : \"ListView\",\n };\n const list = resolvePointer(dataSource, templateChildren.template.path);\n if (!Array.isArray(list)) {\n context.warnings.push(\n `Template on component \"${String(node[\"id\"] ?? \"\")}\" did not resolve to a list.`,\n );\n return { ...container, children: [] };\n }\n const itemCount = Math.min(list.length, TEMPLATE_ITEM_CAP);\n if (list.length > TEMPLATE_ITEM_CAP && !context.templateCapWarned) {\n context.warnings.push(\n `A2UI template expansion was capped at ${TEMPLATE_ITEM_CAP} items.`,\n );\n context.templateCapWarned = true;\n }\n const children: UIElement[] = [];\n for (let index = 0; index < itemCount; index++) {\n if (!retained && !horizontalList && !reserveNode(context)) break;\n const child = convertComponent(\n templateChildren.template.componentId,\n list[index],\n context,\n depth + 1,\n visited,\n );\n if (retained || horizontalList) {\n if (child) children.push(child);\n } else {\n children.push({\n $type: \"ListViewItem\",\n ...(child ? { children: child } : {}),\n });\n }\n }\n return { ...container, children };\n};\n\nfunction convertComponent(\n componentId: string,\n dataSource: unknown,\n context: ConversionContext,\n depth: number,\n visited: Set<string>,\n): UIElement | null {\n if (depth >= DEPTH_CAP) {\n if (!context.depthWarned) {\n context.warnings.push(`A2UI depth cap of ${DEPTH_CAP} was reached.`);\n context.depthWarned = true;\n }\n return null;\n }\n if (visited.has(componentId)) {\n context.warnings.push(`A2UI component cycle detected at \"${componentId}\".`);\n return null;\n }\n const node = context.surface.components.get(componentId);\n if (!node) {\n context.warnings.push(`A2UI component \"${componentId}\" was not found.`);\n return null;\n }\n const component = node[\"component\"];\n\n visited.add(componentId);\n try {\n if (typeof component !== \"string\") {\n context.warnings.push(\n `Unknown A2UI component \"${String(component ?? \"\")}\" was skipped.`,\n );\n return null;\n }\n const templateChildren = node[\"children\"];\n const hasTemplate = isTemplateChildren(templateChildren);\n if (\n !SUPPORTED_COMPONENTS.has(component) &&\n !context.keepUnknownComponents &&\n !hasTemplate\n ) {\n context.warnings.push(\n `Unknown A2UI component \"${component}\" was skipped.`,\n );\n return null;\n }\n const props: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(node)) {\n if (\n key === \"id\" ||\n key === \"component\" ||\n key === \"children\" ||\n key === \"child\"\n ) {\n continue;\n }\n const resolved = materialize(value, dataSource);\n if (resolved !== undefined) setOwnProperty(props, key, resolved);\n }\n const mapped = mappedProps(node, props, context);\n if (!mapped && SUPPORTED_COMPONENTS.has(component)) {\n context.warnings.push(\n `A2UI component \"${component}\" could not be mapped and was skipped.`,\n );\n return null;\n }\n const retained =\n !mapped && context.keepUnknownComponents\n ? {\n $type: component,\n ...Object.fromEntries(\n Object.entries(props).filter(([key]) => !key.startsWith(\"$\")),\n ),\n }\n : undefined;\n if (hasTemplate) {\n return convertTemplate(\n node,\n templateChildren,\n dataSource,\n context,\n depth,\n visited,\n retained,\n component === \"List\" ? mapped : undefined,\n );\n }\n if (!reserveNode(context)) return null;\n const converted = mapped ?? retained;\n if (!converted) return null;\n const children = childrenOf(node, dataSource, context, depth, visited);\n if (mapped?.$type === \"Button\" && mapped[\"label\"] === undefined) {\n const label = textLabel(node, children, context);\n if (label !== undefined) return { ...mapped, label };\n }\n const listChildren =\n component === \"List\" && mapped?.$type === \"ListView\"\n ? children.map((child) => ({ $type: \"ListViewItem\", children: child }))\n : children;\n return {\n ...converted,\n ...(listChildren.length > 0 ? { children: listChildren } : {}),\n };\n } finally {\n visited.delete(componentId);\n }\n}\n\nexport function convertSurfaceToUISpec(\n surface: A2uiSurfaceState,\n options: { readonly keepUnknownComponents?: boolean } = {},\n): {\n spec: UIElement | null;\n warnings: string[];\n} {\n const warnings: string[] = [];\n if (!surface.components.has(\"root\")) {\n return {\n spec: null,\n warnings: ['A2UI root component \"root\" was not found.'],\n };\n }\n const context: ConversionContext = {\n surface,\n surfaceId: sourceSurfaceId(surface),\n warnings,\n emittedNodes: 0,\n depthWarned: false,\n budgetWarned: false,\n templateCapWarned: false,\n keepUnknownComponents: options.keepUnknownComponents === true,\n };\n try {\n const spec = convertComponent(\n \"root\",\n surface.dataModel,\n context,\n 0,\n new Set(),\n );\n return { spec, warnings };\n } catch {\n warnings.push(\"A2UI surface conversion encountered malformed input.\");\n return { spec: null, warnings };\n }\n}\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.20",
3
+ "version": "0.0.21",
4
4
  "description": "Generative UI components for assistant-ui",
5
5
  "keywords": [
6
6
  "generative-ui",
@@ -614,6 +614,211 @@ describe("convertSurfaceToUISpec", () => {
614
614
  );
615
615
  });
616
616
 
617
+ it("follows single child references and event actions", () => {
618
+ const surface = surfaceFrom(
619
+ [
620
+ { id: "root", component: "Card", child: "column" },
621
+ {
622
+ id: "column",
623
+ component: "Column",
624
+ children: ["submit", "close"],
625
+ },
626
+ {
627
+ id: "submit",
628
+ component: "Button",
629
+ child: "submit-text",
630
+ action: {
631
+ event: {
632
+ name: "submit",
633
+ context: { carrier: { path: "/carrier" } },
634
+ },
635
+ },
636
+ },
637
+ { id: "submit-text", component: "Text", text: { path: "/label" } },
638
+ {
639
+ id: "close",
640
+ component: "Button",
641
+ child: "close-icon",
642
+ action: { event: { name: "close" } },
643
+ },
644
+ { id: "close-icon", component: "Icon", name: "x" },
645
+ ],
646
+ { carrier: ["dhl"], label: "Create label" },
647
+ );
648
+
649
+ expect(convertSurfaceToUISpec(surface)).toEqual({
650
+ spec: {
651
+ $type: "Card",
652
+ children: [
653
+ {
654
+ $type: "Col",
655
+ children: [
656
+ {
657
+ $type: "Button",
658
+ label: "Create label",
659
+ $action: {
660
+ type: "a2ui:action",
661
+ name: "submit",
662
+ surfaceId: "",
663
+ sourceComponentId: "submit",
664
+ context: { carrier: ["dhl"] },
665
+ },
666
+ },
667
+ {
668
+ $type: "Button",
669
+ $action: {
670
+ type: "a2ui:action",
671
+ name: "close",
672
+ surfaceId: "",
673
+ sourceComponentId: "close",
674
+ },
675
+ children: [{ $type: "Icon", name: "x" }],
676
+ },
677
+ ],
678
+ },
679
+ ],
680
+ },
681
+ warnings: [],
682
+ });
683
+ });
684
+
685
+ it("takes a button label only from a Text child and keeps action data as bound", () => {
686
+ const surface = surfaceFrom(
687
+ [
688
+ {
689
+ id: "root",
690
+ component: "Column",
691
+ children: ["custom-label", "bound-context"],
692
+ },
693
+ { id: "custom-label", component: "Button", child: "note" },
694
+ { id: "note", component: "Markdown", value: "Read me", tone: "loud" },
695
+ {
696
+ id: "bound-context",
697
+ component: "Button",
698
+ label: "Go",
699
+ action: {
700
+ event: { name: "go", context: { target: { path: "/target" } } },
701
+ },
702
+ },
703
+ ],
704
+ { target: { path: "/secret" }, secret: "hidden" },
705
+ );
706
+
707
+ expect(
708
+ convertSurfaceToUISpec(surface, { keepUnknownComponents: true }),
709
+ ).toEqual({
710
+ spec: {
711
+ $type: "Col",
712
+ children: [
713
+ {
714
+ $type: "Button",
715
+ children: [{ $type: "Markdown", value: "Read me", tone: "loud" }],
716
+ },
717
+ {
718
+ $type: "Button",
719
+ label: "Go",
720
+ $action: {
721
+ type: "a2ui:action",
722
+ name: "go",
723
+ surfaceId: "",
724
+ sourceComponentId: "bound-context",
725
+ context: { target: { path: "/secret" } },
726
+ },
727
+ },
728
+ ],
729
+ },
730
+ warnings: [],
731
+ });
732
+ });
733
+
734
+ it("warns about a child reference it cannot follow", () => {
735
+ const surface = surfaceFrom([
736
+ { id: "root", component: "Column", children: ["missing", "malformed"] },
737
+ { id: "missing", component: "Card", child: "gone" },
738
+ { id: "malformed", component: "Card", child: 7 },
739
+ ]);
740
+
741
+ expect(convertSurfaceToUISpec(surface)).toEqual({
742
+ spec: {
743
+ $type: "Col",
744
+ children: [{ $type: "Card" }, { $type: "Card" }],
745
+ },
746
+ warnings: [
747
+ 'A2UI component "gone" was not found.',
748
+ 'Component "malformed" has a malformed child reference.',
749
+ ],
750
+ });
751
+ });
752
+
753
+ it("keeps the content of kept Modal, Tabs, and single child components", () => {
754
+ const tabs = [
755
+ { title: "Pickup", child: "pickup" },
756
+ { title: "Drop off", child: "drop-off" },
757
+ ];
758
+ const surface = surfaceFrom([
759
+ {
760
+ id: "root",
761
+ component: "Column",
762
+ children: ["modal", "tabs", "panel"],
763
+ },
764
+ { id: "modal", component: "Modal", trigger: "open", content: "details" },
765
+ {
766
+ id: "open",
767
+ component: "Button",
768
+ child: "open-text",
769
+ action: { event: { name: "open" } },
770
+ },
771
+ { id: "open-text", component: "Text", text: "Details" },
772
+ { id: "details", component: "Text", text: "Ships in two days." },
773
+ { id: "tabs", component: "Tabs", tabs },
774
+ { id: "pickup", component: "Text", text: "A courier collects it." },
775
+ { id: "drop-off", component: "Text", text: "Any service point." },
776
+ { id: "panel", component: "ReturnPanel", child: "note" },
777
+ { id: "note", component: "Text", text: "Returns are free." },
778
+ ]);
779
+
780
+ expect(
781
+ convertSurfaceToUISpec(surface, { keepUnknownComponents: true }),
782
+ ).toEqual({
783
+ spec: {
784
+ $type: "Col",
785
+ children: [
786
+ {
787
+ $type: "Modal",
788
+ trigger: "open",
789
+ content: "details",
790
+ children: [
791
+ {
792
+ $type: "Button",
793
+ label: "Details",
794
+ $action: {
795
+ type: "a2ui:action",
796
+ name: "open",
797
+ surfaceId: "",
798
+ sourceComponentId: "open",
799
+ },
800
+ },
801
+ { $type: "Markdown", value: "Ships in two days." },
802
+ ],
803
+ },
804
+ {
805
+ $type: "Tabs",
806
+ tabs,
807
+ children: [
808
+ { $type: "Markdown", value: "A courier collects it." },
809
+ { $type: "Markdown", value: "Any service point." },
810
+ ],
811
+ },
812
+ {
813
+ $type: "ReturnPanel",
814
+ children: [{ $type: "Markdown", value: "Returns are free." }],
815
+ },
816
+ ],
817
+ },
818
+ warnings: [],
819
+ });
820
+ });
821
+
617
822
  it("truncates a component cycle", () => {
618
823
  const surface = surfaceFrom([
619
824
  {
@@ -693,6 +898,22 @@ describe("convertSurfaceToUISpec", () => {
693
898
  expect(result.warnings).toContain("A2UI node budget of 5000 was reached.");
694
899
  });
695
900
 
901
+ it("converts a children list longer than the call argument limit", () => {
902
+ const result = convertSurfaceToUISpec(
903
+ surfaceFrom([
904
+ {
905
+ id: "root",
906
+ component: "Row",
907
+ children: Array.from({ length: 500_000 }, () => "leaf"),
908
+ },
909
+ { id: "leaf", component: "Divider" },
910
+ ]),
911
+ );
912
+
913
+ expect((result.spec as UIElement).children).toHaveLength(4999);
914
+ expect(result.warnings).toEqual(["A2UI node budget of 5000 was reached."]);
915
+ });
916
+
696
917
  it("skips an unknown component with a warning naming it", () => {
697
918
  const result = convertSurfaceToUISpec(
698
919
  surfaceFrom([{ id: "root", component: "VideoPlayer" }]),
@@ -167,6 +167,21 @@ const reserveNode = (context: ConversionContext): boolean => {
167
167
  return true;
168
168
  };
169
169
 
170
+ const childReferences = (node: Record<string, unknown>): unknown[] => {
171
+ const children = node["children"];
172
+ const references: unknown[] = Array.isArray(children) ? [...children] : [];
173
+ if (node["child"] !== undefined) references.push(node["child"]);
174
+ if (node["component"] === "Modal") {
175
+ references.push(node["trigger"], node["content"]);
176
+ }
177
+ if (node["component"] === "Tabs" && Array.isArray(node["tabs"])) {
178
+ for (const tab of node["tabs"]) {
179
+ references.push(isRecord(tab) ? tab["child"] : undefined);
180
+ }
181
+ }
182
+ return references;
183
+ };
184
+
170
185
  const childrenOf = (
171
186
  node: Record<string, unknown>,
172
187
  dataSource: unknown,
@@ -174,10 +189,8 @@ const childrenOf = (
174
189
  depth: number,
175
190
  visited: Set<string>,
176
191
  ): UIElement[] => {
177
- const children = node["children"];
178
- if (!Array.isArray(children)) return [];
179
192
  const result: UIElement[] = [];
180
- for (const childId of children) {
193
+ for (const childId of childReferences(node)) {
181
194
  if (typeof childId !== "string") {
182
195
  context.warnings.push(
183
196
  `Component "${String(node["id"] ?? "")}" has a malformed child reference.`,
@@ -196,29 +209,49 @@ const childrenOf = (
196
209
  return result;
197
210
  };
198
211
 
212
+ const textLabel = (
213
+ node: Record<string, unknown>,
214
+ children: readonly UIElement[],
215
+ context: ConversionContext,
216
+ ): string | undefined => {
217
+ const references = childReferences(node);
218
+ const [reference] = references;
219
+ const [child] = children;
220
+ if (
221
+ references.length !== 1 ||
222
+ children.length !== 1 ||
223
+ typeof reference !== "string" ||
224
+ !child ||
225
+ context.surface.components.get(reference)?.["component"] !== "Text"
226
+ ) {
227
+ return undefined;
228
+ }
229
+ const text = child.$type === "Header" ? child["text"] : child["value"];
230
+ return typeof text === "string" ? text : undefined;
231
+ };
232
+
199
233
  const mappedAction = (
200
234
  node: Record<string, unknown>,
201
235
  props: Record<string, unknown>,
202
- dataSource: unknown,
203
236
  context: ConversionContext,
204
237
  ): UIElement["$action"] | undefined => {
205
238
  const action = props["action"];
239
+ const event =
240
+ isRecord(action) && isRecord(action["event"]) ? action["event"] : action;
206
241
  const actionName =
207
- typeof action === "string"
208
- ? action
209
- : isRecord(action) && typeof action["name"] === "string"
210
- ? action["name"]
242
+ typeof event === "string"
243
+ ? event
244
+ : isRecord(event) && typeof event["name"] === "string"
245
+ ? event["name"]
211
246
  : undefined;
212
247
  if (!actionName) return undefined;
213
- const rawContext = isRecord(action) ? action["context"] : undefined;
214
- const resolvedContext =
215
- rawContext === undefined ? undefined : materialize(rawContext, dataSource);
248
+ const actionContext = isRecord(event) ? event["context"] : undefined;
216
249
  return {
217
250
  type: "a2ui:action",
218
251
  name: actionName,
219
252
  surfaceId: context.surfaceId,
220
253
  sourceComponentId: typeof node["id"] === "string" ? node["id"] : "",
221
- ...(resolvedContext !== undefined ? { context: resolvedContext } : {}),
254
+ ...(actionContext !== undefined ? { context: actionContext } : {}),
222
255
  };
223
256
  };
224
257
 
@@ -240,7 +273,6 @@ const choiceOptions = (value: unknown): { label: string; value: string }[] => {
240
273
  const mappedProps = (
241
274
  node: Record<string, unknown>,
242
275
  props: Record<string, unknown>,
243
- dataSource: unknown,
244
276
  context: ConversionContext,
245
277
  ): UIElement | undefined => {
246
278
  const component = node["component"];
@@ -349,7 +381,7 @@ const mappedProps = (
349
381
  const buttonStyle = props["buttonStyle"];
350
382
  const block = props["block"];
351
383
  const submit = props["submit"];
352
- const action = mappedAction(node, props, dataSource, context);
384
+ const action = mappedAction(node, props, context);
353
385
  return {
354
386
  $type: "Button",
355
387
  ...(label !== undefined ? { label } : {}),
@@ -544,11 +576,18 @@ function convertComponent(
544
576
  }
545
577
  const props: Record<string, unknown> = {};
546
578
  for (const [key, value] of Object.entries(node)) {
547
- if (key === "id" || key === "component" || key === "children") continue;
579
+ if (
580
+ key === "id" ||
581
+ key === "component" ||
582
+ key === "children" ||
583
+ key === "child"
584
+ ) {
585
+ continue;
586
+ }
548
587
  const resolved = materialize(value, dataSource);
549
588
  if (resolved !== undefined) setOwnProperty(props, key, resolved);
550
589
  }
551
- const mapped = mappedProps(node, props, dataSource, context);
590
+ const mapped = mappedProps(node, props, context);
552
591
  if (!mapped && SUPPORTED_COMPONENTS.has(component)) {
553
592
  context.warnings.push(
554
593
  `A2UI component "${component}" could not be mapped and was skipped.`,
@@ -580,6 +619,10 @@ function convertComponent(
580
619
  const converted = mapped ?? retained;
581
620
  if (!converted) return null;
582
621
  const children = childrenOf(node, dataSource, context, depth, visited);
622
+ if (mapped?.$type === "Button" && mapped["label"] === undefined) {
623
+ const label = textLabel(node, children, context);
624
+ if (label !== undefined) return { ...mapped, label };
625
+ }
583
626
  const listChildren =
584
627
  component === "List" && mapped?.$type === "ListView"
585
628
  ? children.map((child) => ({ $type: "ListViewItem", children: child }))