cortena-ui 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -3
- package/dist/a2ui/catalogue-doc.d.ts +44 -0
- package/dist/a2ui/catalogue-doc.js +169 -0
- package/dist/a2ui/catalogue-doc.js.map +1 -0
- package/dist/a2ui/catalogue.d.ts +44 -0
- package/dist/a2ui/catalogue.js +942 -0
- package/dist/a2ui/catalogue.js.map +1 -0
- package/dist/a2ui/index.d.ts +7 -0
- package/dist/a2ui/message.d.ts +232 -0
- package/dist/a2ui/message.js +365 -0
- package/dist/a2ui/message.js.map +1 -0
- package/dist/a2ui/renderer.d.ts +46 -0
- package/dist/a2ui/renderer.js +252 -0
- package/dist/a2ui/renderer.js.map +1 -0
- package/dist/a2ui/views.d.ts +80 -0
- package/dist/a2ui/views.js +596 -0
- package/dist/a2ui/views.js.map +1 -0
- package/dist/a2ui.d.ts +8 -0
- package/dist/a2ui.js +7 -0
- package/dist/chart.d.ts +9 -0
- package/dist/chart.js +9 -0
- package/dist/components/accordion.d.ts +22 -0
- package/dist/components/accordion.js +63 -0
- package/dist/components/accordion.js.map +1 -0
- package/dist/components/alert.d.ts +15 -0
- package/dist/components/alert.js +64 -0
- package/dist/components/alert.js.map +1 -0
- package/dist/components/avatar.d.ts +18 -0
- package/dist/components/avatar.js +40 -0
- package/dist/components/avatar.js.map +1 -0
- package/dist/components/badge.d.ts +12 -0
- package/dist/components/badge.js +47 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/breadcrumb.d.ts +71 -0
- package/dist/components/breadcrumb.js +123 -0
- package/dist/components/breadcrumb.js.map +1 -0
- package/dist/components/button-link.d.ts +28 -0
- package/dist/components/button-link.js +24 -0
- package/dist/components/button-link.js.map +1 -0
- package/dist/components/button.d.ts +24 -0
- package/dist/components/button.js +65 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/calendar.d.ts +28 -0
- package/dist/components/calendar.js +123 -0
- package/dist/components/calendar.js.map +1 -0
- package/dist/components/card.d.ts +32 -0
- package/dist/components/card.js +57 -0
- package/dist/components/card.js.map +1 -0
- package/dist/components/chart/chart.d.ts +71 -0
- package/dist/components/chart/chart.js +167 -0
- package/dist/components/chart/chart.js.map +1 -0
- package/dist/components/chart/container.d.ts +88 -0
- package/dist/components/chart/container.js +189 -0
- package/dist/components/chart/container.js.map +1 -0
- package/dist/components/chart/data.js +128 -0
- package/dist/components/chart/data.js.map +1 -0
- package/dist/components/chart/index.d.ts +9 -0
- package/dist/components/chart/index.js +10 -0
- package/dist/components/chart/nivo-charts.js +225 -0
- package/dist/components/chart/nivo-charts.js.map +1 -0
- package/dist/components/chart/nivo-lazy.js +50 -0
- package/dist/components/chart/nivo-lazy.js.map +1 -0
- package/dist/components/chart/nivo-theme.d.ts +156 -0
- package/dist/components/chart/nivo-theme.js +161 -0
- package/dist/components/chart/nivo-theme.js.map +1 -0
- package/dist/components/chart/recharts-charts.js +276 -0
- package/dist/components/chart/recharts-charts.js.map +1 -0
- package/dist/components/chart/recharts-lazy.js +58 -0
- package/dist/components/chart/recharts-lazy.js.map +1 -0
- package/dist/components/chart/recharts-parts.d.ts +10 -0
- package/dist/components/chart/recharts-parts.js +25 -0
- package/dist/components/chart/recharts-parts.js.map +1 -0
- package/dist/components/chart/tokens.d.ts +62 -0
- package/dist/components/chart/tokens.js +192 -0
- package/dist/components/chart/tokens.js.map +1 -0
- package/dist/components/chart/types.d.ts +114 -0
- package/dist/components/chart/types.js +27 -0
- package/dist/components/chart/types.js.map +1 -0
- package/dist/components/checkbox.d.ts +20 -0
- package/dist/components/checkbox.js +24 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/chip.d.ts +17 -0
- package/dist/components/chip.js +47 -0
- package/dist/components/chip.js.map +1 -0
- package/dist/components/combobox.d.ts +76 -0
- package/dist/components/combobox.js +201 -0
- package/dist/components/combobox.js.map +1 -0
- package/dist/components/command.d.ts +50 -0
- package/dist/components/command.js +117 -0
- package/dist/components/command.js.map +1 -0
- package/dist/components/data-table/data-table.d.ts +65 -0
- package/dist/components/data-table/data-table.js +588 -0
- package/dist/components/data-table/data-table.js.map +1 -0
- package/dist/components/data-table/export.d.ts +23 -0
- package/dist/components/data-table/export.js +95 -0
- package/dist/components/data-table/export.js.map +1 -0
- package/dist/components/data-table/features.d.ts +66 -0
- package/dist/components/data-table/features.js +103 -0
- package/dist/components/data-table/features.js.map +1 -0
- package/dist/components/data-table/index.d.ts +8 -0
- package/dist/components/data-table/parts.d.ts +79 -0
- package/dist/components/data-table/parts.js +400 -0
- package/dist/components/data-table/parts.js.map +1 -0
- package/dist/components/data-table/system-columns.js +84 -0
- package/dist/components/data-table/system-columns.js.map +1 -0
- package/dist/components/data-table/types.d.ts +172 -0
- package/dist/components/data-table/use-data-table.d.ts +19 -0
- package/dist/components/data-table/use-data-table.js +171 -0
- package/dist/components/data-table/use-data-table.js.map +1 -0
- package/dist/components/data-table/use-server-source.js +200 -0
- package/dist/components/data-table/use-server-source.js.map +1 -0
- package/dist/components/date-field.d.ts +54 -0
- package/dist/components/date-field.js +235 -0
- package/dist/components/date-field.js.map +1 -0
- package/dist/components/date-picker.d.ts +42 -0
- package/dist/components/date-picker.js +125 -0
- package/dist/components/date-picker.js.map +1 -0
- package/dist/components/dialog.d.ts +36 -0
- package/dist/components/dialog.js +97 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/dropdown-menu.d.ts +54 -0
- package/dist/components/dropdown-menu.js +191 -0
- package/dist/components/dropdown-menu.js.map +1 -0
- package/dist/components/dropzone.d.ts +48 -0
- package/dist/components/dropzone.js +185 -0
- package/dist/components/dropzone.js.map +1 -0
- package/dist/components/empty-state.d.ts +22 -0
- package/dist/components/empty-state.js +46 -0
- package/dist/components/empty-state.js.map +1 -0
- package/dist/components/error-banner.d.ts +17 -0
- package/dist/components/error-banner.js +52 -0
- package/dist/components/error-banner.js.map +1 -0
- package/dist/components/field.d.ts +64 -0
- package/dist/components/field.js +133 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/form.d.ts +37 -0
- package/dist/components/form.js +103 -0
- package/dist/components/form.js.map +1 -0
- package/dist/components/input.d.ts +17 -0
- package/dist/components/input.js +26 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/kbd.d.ts +11 -0
- package/dist/components/kbd.js +20 -0
- package/dist/components/kbd.js.map +1 -0
- package/dist/components/label.d.ts +14 -0
- package/dist/components/label.js +28 -0
- package/dist/components/label.js.map +1 -0
- package/dist/components/loading-skeleton.d.ts +22 -0
- package/dist/components/loading-skeleton.js +123 -0
- package/dist/components/loading-skeleton.js.map +1 -0
- package/dist/components/markdown.d.ts +44 -0
- package/dist/components/markdown.js +231 -0
- package/dist/components/markdown.js.map +1 -0
- package/dist/components/page-header.d.ts +26 -0
- package/dist/components/page-header.js +53 -0
- package/dist/components/page-header.js.map +1 -0
- package/dist/components/popover.d.ts +29 -0
- package/dist/components/popover.js +74 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/progress.d.ts +22 -0
- package/dist/components/progress.js +49 -0
- package/dist/components/progress.js.map +1 -0
- package/dist/components/radio-group.d.ts +20 -0
- package/dist/components/radio-group.js +29 -0
- package/dist/components/radio-group.js.map +1 -0
- package/dist/components/scroll-area.d.ts +25 -0
- package/dist/components/scroll-area.js +39 -0
- package/dist/components/scroll-area.js.map +1 -0
- package/dist/components/section-card.d.ts +29 -0
- package/dist/components/section-card.js +55 -0
- package/dist/components/section-card.js.map +1 -0
- package/dist/components/segmented.d.ts +27 -0
- package/dist/components/segmented.js +32 -0
- package/dist/components/segmented.js.map +1 -0
- package/dist/components/select.d.ts +62 -0
- package/dist/components/select.js +97 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/separator.d.ts +19 -0
- package/dist/components/separator.js +23 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/sheet.d.ts +35 -0
- package/dist/components/sheet.js +131 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/skeleton.d.ts +12 -0
- package/dist/components/skeleton.js +22 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/sortable-list.d.ts +67 -0
- package/dist/components/sortable-list.js +206 -0
- package/dist/components/sortable-list.js.map +1 -0
- package/dist/components/spinner.d.ts +29 -0
- package/dist/components/spinner.js +34 -0
- package/dist/components/spinner.js.map +1 -0
- package/dist/components/status-dot.d.ts +26 -0
- package/dist/components/status-dot.js +47 -0
- package/dist/components/status-dot.js.map +1 -0
- package/dist/components/switch.d.ts +21 -0
- package/dist/components/switch.js +21 -0
- package/dist/components/switch.js.map +1 -0
- package/dist/components/tabs.d.ts +24 -0
- package/dist/components/tabs.js +60 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/textarea.d.ts +19 -0
- package/dist/components/textarea.js +47 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/components/toast.d.ts +47 -0
- package/dist/components/toast.js +106 -0
- package/dist/components/toast.js.map +1 -0
- package/dist/components/toolbar.d.ts +19 -0
- package/dist/components/toolbar.js +45 -0
- package/dist/components/toolbar.js.map +1 -0
- package/dist/components/tooltip.d.ts +28 -0
- package/dist/components/tooltip.js +59 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/core.d.ts +44 -0
- package/dist/core.js +44 -0
- package/dist/data-table.d.ts +9 -0
- package/dist/data-table.js +7 -0
- package/dist/form.d.ts +7 -0
- package/dist/form.js +7 -0
- package/dist/hooks/use-cortena-theme.d.ts +98 -0
- package/dist/hooks/use-cortena-theme.js +145 -0
- package/dist/hooks/use-cortena-theme.js.map +1 -0
- package/dist/index.d.ts +75 -2678
- package/dist/index.js +66 -8598
- package/dist/lib/cn.d.ts +10 -0
- package/dist/lib/cn.js +15 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/render.d.ts +23 -0
- package/dist/lib/render.js +20 -0
- package/dist/lib/render.js.map +1 -0
- package/dist/lib/shakeable.js +39 -0
- package/dist/lib/shakeable.js.map +1 -0
- package/dist/markdown.d.ts +3 -0
- package/dist/markdown.js +3 -0
- package/dist/sortable-list.d.ts +3 -0
- package/dist/sortable-list.js +3 -0
- package/package.json +37 -14
- package/src/a2ui/catalogue.ts +140 -103
- package/src/a2ui/views.tsx +5 -2
- package/src/components/alert.tsx +1 -1
- package/src/components/badge.tsx +1 -1
- package/src/components/button.tsx +1 -1
- package/src/components/chart/chart.tsx +72 -25
- package/src/components/chart/container.tsx +24 -39
- package/src/components/chart/index.tsx +4 -2
- package/src/components/chart/nivo-charts.tsx +41 -13
- package/src/components/chart/nivo-lazy.tsx +52 -0
- package/src/components/chart/recharts-charts.tsx +98 -3
- package/src/components/chart/recharts-lazy.tsx +72 -0
- package/src/components/chart/recharts-parts.tsx +34 -0
- package/src/components/chart/tokens.ts +1 -1
- package/src/components/chart/types.ts +14 -0
- package/src/components/chip.tsx +1 -1
- package/src/components/combobox.tsx +2 -2
- package/src/components/data-table/export.ts +18 -2
- package/src/components/data-table/features.ts +77 -45
- package/src/components/data-table/parts.tsx +15 -0
- package/src/components/data-table/use-data-table.ts +7 -2
- package/src/components/data-table/use-server-source.ts +17 -4
- package/src/components/date-field.tsx +1 -1
- package/src/components/error-banner.tsx +1 -1
- package/src/components/field.tsx +2 -2
- package/src/components/form.tsx +2 -2
- package/src/components/input.tsx +1 -1
- package/src/components/label.tsx +1 -1
- package/src/components/markdown.tsx +5 -4
- package/src/components/sheet.tsx +2 -2
- package/src/components/sortable-list.tsx +2 -2
- package/src/components/textarea.tsx +1 -1
- package/src/components/toast.tsx +1 -1
- package/src/entries/a2ui.ts +11 -0
- package/src/entries/chart.ts +10 -0
- package/src/entries/core.ts +91 -0
- package/src/entries/data-table.ts +9 -0
- package/src/entries/form.ts +24 -0
- package/src/entries/markdown.ts +9 -0
- package/src/entries/sortable-list.ts +13 -0
- package/src/index.ts +32 -98
- package/src/lib/shakeable.ts +33 -0
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { A2UIErrorCard } from "./views.js";
|
|
5
|
+
import { defaultCatalogue } from "./catalogue.js";
|
|
6
|
+
import { foldMessages, isDataBinding, readAction, readChildren, readComponent, resolvePointer, resolveValue, setAtPointer } from "./message.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
//#region src/a2ui/renderer.tsx
|
|
10
|
+
/**
|
|
11
|
+
* The A2UI React renderer.
|
|
12
|
+
*
|
|
13
|
+
* Takes A2UI messages, folds them onto surfaces, walks the component tree and
|
|
14
|
+
* draws each node through the catalogue. Nothing an agent sends reaches the DOM
|
|
15
|
+
* as markup: a node is a catalogue name plus properties that must pass the
|
|
16
|
+
* entry's zod schema, and anything else becomes an inline error card.
|
|
17
|
+
*
|
|
18
|
+
* ## Why this is written rather than adopted
|
|
19
|
+
*
|
|
20
|
+
* `@a2ui/react` 0.11.0 (Google, Apache-2.0, published 2026-09-01) is a real,
|
|
21
|
+
* maintained v0.9 renderer and it does let a host supply a catalogue. It was
|
|
22
|
+
* evaluated for DESIGN-33 and not adopted, for three reasons:
|
|
23
|
+
*
|
|
24
|
+
* 1. **zod major.** `@a2ui/web_core`'s generic binder reads zod 3 internals —
|
|
25
|
+
* `schema._def.typeName`, `_def.shape()`, `_def.innerType` — to decide how to
|
|
26
|
+
* bind each property. cortena-ui's zod peer is `^3.25 || ^4`, and zod 4 has
|
|
27
|
+
* no `_def.typeName` and exposes `shape` as a property, so a catalogue
|
|
28
|
+
* authored with the consumer's zod 4 fails inside the binder. Adopting would
|
|
29
|
+
* pin the whole package's schema layer to zod 3 while `form.tsx` and
|
|
30
|
+
* `@hookform/resolvers` follow the consumer's.
|
|
31
|
+
* 2. **Dialect.** Cortena already speaks A2UI v0.8: core bundles the Lit
|
|
32
|
+
* renderer at `src/canvas-host/a2ui/` and the `canvas` tool pushes
|
|
33
|
+
* `beginRendering` / `surfaceUpdate` / `dataModelUpdate` as JSONL.
|
|
34
|
+
* `@a2ui/react` splits v0_8 and v0_9 into separate entry points with separate
|
|
35
|
+
* catalogues, so neither one reads both. Every payload written for the
|
|
36
|
+
* native nodes would have to be rewritten before it rendered on the web.
|
|
37
|
+
* 3. **Weight and surface.** It brings `@a2ui/web_core` (3.8 MB unpacked),
|
|
38
|
+
* markdown-it, `@preact/signals-core` and date-fns into a package whose build
|
|
39
|
+
* externalises everything and whose markdown already goes through
|
|
40
|
+
* react-markdown with a sanitize schema. And the API this task needs —
|
|
41
|
+
* `resolveDataSource` for server tables, `onAction` for the AG-UI round trip —
|
|
42
|
+
* has no counterpart there, so it would be wrapped either way.
|
|
43
|
+
*
|
|
44
|
+
* What we keep is the part that matters for interop: the **wire format** is
|
|
45
|
+
* A2UI's, the action we emit is shaped like A2UI's client-to-server `action`
|
|
46
|
+
* (`{ name, surfaceId, sourceComponentId, context }`), and the catalogue is a
|
|
47
|
+
* schema-per-component registry. Swapping the engine later is mechanical.
|
|
48
|
+
*/
|
|
49
|
+
/** Depth limit; a tree deeper than this is a malformed payload, not a design. */
|
|
50
|
+
const MAX_DEPTH = 32;
|
|
51
|
+
/**
|
|
52
|
+
* A2UIRenderer — draws A2UI messages through cortena-ui.
|
|
53
|
+
*
|
|
54
|
+
* ```tsx
|
|
55
|
+
* <A2UIRenderer
|
|
56
|
+
* message={customEvent.value}
|
|
57
|
+
* catalogue={defaultCatalogue}
|
|
58
|
+
* onAction={(action) => agent.send(action)}
|
|
59
|
+
* resolveDataSource={(id) => sources[id]}
|
|
60
|
+
* />
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
function A2UIRenderer({ message, catalogue = defaultCatalogue, onAction, resolveDataSource, surfaceId, debounceMs = 300, className }) {
|
|
64
|
+
const fold = React.useMemo(() => foldMessages(message), [message]);
|
|
65
|
+
const [models, setModels] = React.useState(() => seedModels(fold.surfaces));
|
|
66
|
+
const seenFold = React.useRef(fold);
|
|
67
|
+
if (seenFold.current !== fold) {
|
|
68
|
+
seenFold.current = fold;
|
|
69
|
+
setModels(seedModels(fold.surfaces));
|
|
70
|
+
}
|
|
71
|
+
const resolve = React.useCallback((sourceId) => resolveDataSource?.(sourceId), [resolveDataSource]);
|
|
72
|
+
const surfaces = surfaceId ? fold.surfaces.filter((surface) => surface.id === surfaceId) : fold.surfaces;
|
|
73
|
+
const missingSurface = Boolean(surfaceId) && surfaces.length === 0 && fold.surfaces.length > 0;
|
|
74
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
75
|
+
"data-slot": "a2ui-renderer",
|
|
76
|
+
className: cn("flex min-w-0 flex-col gap-3", className),
|
|
77
|
+
children: [
|
|
78
|
+
fold.errors.length > 0 ? /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
79
|
+
title: "Malformed A2UI payload",
|
|
80
|
+
detail: fold.errors.slice(0, 5).join(" ")
|
|
81
|
+
}) : null,
|
|
82
|
+
missingSurface ? /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
83
|
+
title: "Unknown surface",
|
|
84
|
+
detail: `No surface "${surfaceId}" in this payload.`
|
|
85
|
+
}) : null,
|
|
86
|
+
surfaces.map((surface) => /* @__PURE__ */ jsx(A2UISurfaceView, {
|
|
87
|
+
surface,
|
|
88
|
+
catalogue,
|
|
89
|
+
model: models[surface.id] ?? surface.dataModel,
|
|
90
|
+
setModel: (updater) => setModels((current) => ({
|
|
91
|
+
...current,
|
|
92
|
+
[surface.id]: updater(current[surface.id] ?? surface.dataModel)
|
|
93
|
+
})),
|
|
94
|
+
onAction,
|
|
95
|
+
resolveDataSource: resolve,
|
|
96
|
+
debounceMs
|
|
97
|
+
}, surface.id))
|
|
98
|
+
]
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function seedModels(surfaces) {
|
|
102
|
+
const models = {};
|
|
103
|
+
for (const surface of surfaces) models[surface.id] = surface.dataModel;
|
|
104
|
+
return models;
|
|
105
|
+
}
|
|
106
|
+
function A2UISurfaceView({ surface, catalogue, model, setModel, onAction, resolveDataSource, debounceMs }) {
|
|
107
|
+
const context = {
|
|
108
|
+
surface,
|
|
109
|
+
catalogue,
|
|
110
|
+
model,
|
|
111
|
+
setModel,
|
|
112
|
+
onAction,
|
|
113
|
+
resolveDataSource,
|
|
114
|
+
debounceMs
|
|
115
|
+
};
|
|
116
|
+
if (!surface.root) return /* @__PURE__ */ jsx("div", {
|
|
117
|
+
"data-slot": "a2ui-surface",
|
|
118
|
+
"data-surface-id": surface.id,
|
|
119
|
+
children: /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
120
|
+
title: "Empty A2UI surface",
|
|
121
|
+
detail: `Surface "${surface.id}" has no root component. Send updateComponents with a component whose id is "root", or name one in createSurface.`
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
return /* @__PURE__ */ jsx("div", {
|
|
125
|
+
"data-slot": "a2ui-surface",
|
|
126
|
+
"data-surface-id": surface.id,
|
|
127
|
+
className: "flex min-w-0 flex-col",
|
|
128
|
+
children: /* @__PURE__ */ jsx(A2UINode, {
|
|
129
|
+
context,
|
|
130
|
+
id: surface.root,
|
|
131
|
+
contextPath: "/",
|
|
132
|
+
ancestors: [],
|
|
133
|
+
depth: 0
|
|
134
|
+
})
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function A2UINode({ context, id, contextPath, ancestors, depth }) {
|
|
138
|
+
const spec = context.surface.components.get(id);
|
|
139
|
+
if (!spec) return /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
140
|
+
title: "Unknown component id",
|
|
141
|
+
detail: `No component "${id}" in this surface.`
|
|
142
|
+
});
|
|
143
|
+
if (ancestors.includes(id)) return /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
144
|
+
title: "Circular component reference",
|
|
145
|
+
detail: `"${id}" is already an ancestor of itself: ${[...ancestors, id].join(" → ")}.`,
|
|
146
|
+
componentId: id
|
|
147
|
+
});
|
|
148
|
+
if (depth > MAX_DEPTH) return /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
149
|
+
title: "Component tree too deep",
|
|
150
|
+
detail: `More than ${MAX_DEPTH} levels below the root.`,
|
|
151
|
+
componentId: id
|
|
152
|
+
});
|
|
153
|
+
const declaration = readComponent(spec);
|
|
154
|
+
if (!declaration) return /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
155
|
+
title: "Component has no type",
|
|
156
|
+
detail: "Expected `component` to be a catalogue name, or an object keyed by one.",
|
|
157
|
+
componentId: id
|
|
158
|
+
});
|
|
159
|
+
const entry = context.catalogue[declaration.name];
|
|
160
|
+
if (!entry) return /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
161
|
+
title: `Unknown component "${declaration.name}"`,
|
|
162
|
+
detail: `The catalogue has: ${Object.keys(context.catalogue).sort().join(", ")}.`,
|
|
163
|
+
componentId: id
|
|
164
|
+
});
|
|
165
|
+
const raw = declaration.properties;
|
|
166
|
+
const bindings = {};
|
|
167
|
+
const resolved = {};
|
|
168
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
169
|
+
if (key === "children") continue;
|
|
170
|
+
if (isDataBinding(value)) bindings[key] = resolvePointer(value.path, contextPath);
|
|
171
|
+
const next = resolveValue(value, context.model, contextPath);
|
|
172
|
+
resolved[key] = key.startsWith("on") ? readAction(next) : next;
|
|
173
|
+
}
|
|
174
|
+
const parsed = entry.props.safeParse(resolved);
|
|
175
|
+
if (!parsed.success) {
|
|
176
|
+
const issues = parsed.error.issues.slice(0, 4).map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
177
|
+
return /* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
178
|
+
title: `Invalid props for ${declaration.name}`,
|
|
179
|
+
detail: issues,
|
|
180
|
+
componentId: id
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const node = {
|
|
184
|
+
surfaceId: context.surface.id,
|
|
185
|
+
componentId: id,
|
|
186
|
+
dataContextPath: contextPath
|
|
187
|
+
};
|
|
188
|
+
const children = entry.children === "many" ? renderChildren(context, spec, raw, contextPath, [...ancestors, id], depth) : [];
|
|
189
|
+
const emit = (action, fallbackName, payload) => {
|
|
190
|
+
context.onAction?.({
|
|
191
|
+
surfaceId: context.surface.id,
|
|
192
|
+
componentId: id,
|
|
193
|
+
name: action?.name ?? fallbackName,
|
|
194
|
+
payload: {
|
|
195
|
+
...action?.context ?? {},
|
|
196
|
+
...payload ?? {}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
const writeBack = (property, value) => {
|
|
201
|
+
const pointer = bindings[property];
|
|
202
|
+
if (!pointer) return;
|
|
203
|
+
context.setModel((model) => setAtPointer(model, pointer, value));
|
|
204
|
+
};
|
|
205
|
+
const View = entry.view;
|
|
206
|
+
return /* @__PURE__ */ jsx(View, {
|
|
207
|
+
props: parsed.data,
|
|
208
|
+
node,
|
|
209
|
+
dataModel: context.model,
|
|
210
|
+
emit,
|
|
211
|
+
writeBack,
|
|
212
|
+
resolveDataSource: context.resolveDataSource,
|
|
213
|
+
debounceMs: context.debounceMs,
|
|
214
|
+
children
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Render a component's children.
|
|
219
|
+
*
|
|
220
|
+
* An explicit list renders each id once. A template renders the referenced
|
|
221
|
+
* component once per item in a bound array, each with its own data context, so
|
|
222
|
+
* an agent describes a row of a table or a list item once instead of repeating
|
|
223
|
+
* it per item.
|
|
224
|
+
*/
|
|
225
|
+
function renderChildren(context, spec, properties, contextPath, ancestors, depth) {
|
|
226
|
+
const children = readChildren(spec, properties);
|
|
227
|
+
if (children.kind === "none") return [];
|
|
228
|
+
if (children.kind === "list") return children.ids.map((childId) => /* @__PURE__ */ jsx(A2UINode, {
|
|
229
|
+
context,
|
|
230
|
+
id: childId,
|
|
231
|
+
contextPath,
|
|
232
|
+
ancestors,
|
|
233
|
+
depth: depth + 1
|
|
234
|
+
}, childId));
|
|
235
|
+
const pointer = resolvePointer(children.path, contextPath);
|
|
236
|
+
const items = resolveValue({ path: children.path }, context.model, contextPath);
|
|
237
|
+
if (!Array.isArray(items)) return [/* @__PURE__ */ jsx(A2UIErrorCard, {
|
|
238
|
+
title: "Template list is not an array",
|
|
239
|
+
detail: `"${pointer}" does not resolve to an array in the data model.`
|
|
240
|
+
}, "template-error")];
|
|
241
|
+
return items.map((_item, index) => /* @__PURE__ */ jsx(A2UINode, {
|
|
242
|
+
context,
|
|
243
|
+
id: children.componentId,
|
|
244
|
+
contextPath: `${pointer === "/" ? "" : pointer}/${index}`,
|
|
245
|
+
ancestors,
|
|
246
|
+
depth: depth + 1
|
|
247
|
+
}, `${children.componentId}:${index}`));
|
|
248
|
+
}
|
|
249
|
+
//#endregion
|
|
250
|
+
export { A2UIRenderer };
|
|
251
|
+
|
|
252
|
+
//# sourceMappingURL=renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.js","names":[],"sources":["../../src/a2ui/renderer.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The A2UI React renderer.\n *\n * Takes A2UI messages, folds them onto surfaces, walks the component tree and\n * draws each node through the catalogue. Nothing an agent sends reaches the DOM\n * as markup: a node is a catalogue name plus properties that must pass the\n * entry's zod schema, and anything else becomes an inline error card.\n *\n * ## Why this is written rather than adopted\n *\n * `@a2ui/react` 0.11.0 (Google, Apache-2.0, published 2026-09-01) is a real,\n * maintained v0.9 renderer and it does let a host supply a catalogue. It was\n * evaluated for DESIGN-33 and not adopted, for three reasons:\n *\n * 1. **zod major.** `@a2ui/web_core`'s generic binder reads zod 3 internals —\n * `schema._def.typeName`, `_def.shape()`, `_def.innerType` — to decide how to\n * bind each property. cortena-ui's zod peer is `^3.25 || ^4`, and zod 4 has\n * no `_def.typeName` and exposes `shape` as a property, so a catalogue\n * authored with the consumer's zod 4 fails inside the binder. Adopting would\n * pin the whole package's schema layer to zod 3 while `form.tsx` and\n * `@hookform/resolvers` follow the consumer's.\n * 2. **Dialect.** Cortena already speaks A2UI v0.8: core bundles the Lit\n * renderer at `src/canvas-host/a2ui/` and the `canvas` tool pushes\n * `beginRendering` / `surfaceUpdate` / `dataModelUpdate` as JSONL.\n * `@a2ui/react` splits v0_8 and v0_9 into separate entry points with separate\n * catalogues, so neither one reads both. Every payload written for the\n * native nodes would have to be rewritten before it rendered on the web.\n * 3. **Weight and surface.** It brings `@a2ui/web_core` (3.8 MB unpacked),\n * markdown-it, `@preact/signals-core` and date-fns into a package whose build\n * externalises everything and whose markdown already goes through\n * react-markdown with a sanitize schema. And the API this task needs —\n * `resolveDataSource` for server tables, `onAction` for the AG-UI round trip —\n * has no counterpart there, so it would be wrapped either way.\n *\n * What we keep is the part that matters for interop: the **wire format** is\n * A2UI's, the action we emit is shaped like A2UI's client-to-server `action`\n * (`{ name, surfaceId, sourceComponentId, context }`), and the catalogue is a\n * schema-per-component registry. Swapping the engine later is mechanical.\n */\n\nimport * as React from \"react\";\nimport type { DataSource } from \"@/components/data-table\";\nimport { cn } from \"@/lib/cn\";\nimport {\n A2UI_DEFAULT_SURFACE_ID,\n foldMessages,\n isDataBinding,\n readAction,\n readChildren,\n readComponent,\n resolvePointer,\n resolveValue,\n setAtPointer,\n type A2UIAction,\n type A2UIComponentSpec,\n type A2UIMessageInput,\n type A2UISurface,\n} from \"./message\";\nimport { defaultCatalogue, type A2UICatalogue } from \"./catalogue\";\nimport { A2UIErrorCard, type A2UINodeInfo, type A2UIResolvedAction, type A2UIRow } from \"./views\";\n\nexport interface A2UIRendererProps {\n /**\n * The payload. One message, the list an AG-UI `CUSTOM` event carries, or the\n * JSONL text `canvas.a2ui.pushJSONL` sends. Later messages fold onto earlier\n * ones, so a push stream can be accumulated by the host and handed here whole.\n */\n message: A2UIMessageInput;\n /** The component vocabulary. Defaults to the whole cortena-ui catalogue. */\n catalogue?: A2UICatalogue;\n /** Receives every user event, shaped like A2UI's client-to-server action. */\n onAction?: (action: A2UIAction) => void;\n /**\n * Resolves a `{ kind: \"server\", sourceId }` table handle into a real data\n * source. Without it, a server table renders an error card rather than an\n * empty one, because a silently empty table reads as \"no results\".\n */\n resolveDataSource?: (sourceId: string) => DataSource<A2UIRow> | undefined;\n /** Render only this surface. Default: every surface, in arrival order. */\n surfaceId?: string;\n /** Debounce before a continuous input becomes an action. @default 300 */\n debounceMs?: number;\n className?: string;\n}\n\n/** Depth limit; a tree deeper than this is a malformed payload, not a design. */\nconst MAX_DEPTH = 32;\n\ninterface NodeContext {\n surface: A2UISurface;\n catalogue: A2UICatalogue;\n model: Record<string, unknown>;\n setModel: (updater: (model: Record<string, unknown>) => Record<string, unknown>) => void;\n onAction: ((action: A2UIAction) => void) | undefined;\n resolveDataSource: (sourceId: string) => DataSource<A2UIRow> | undefined;\n debounceMs: number;\n}\n\n/**\n * A2UIRenderer — draws A2UI messages through cortena-ui.\n *\n * ```tsx\n * <A2UIRenderer\n * message={customEvent.value}\n * catalogue={defaultCatalogue}\n * onAction={(action) => agent.send(action)}\n * resolveDataSource={(id) => sources[id]}\n * />\n * ```\n */\nexport function A2UIRenderer({\n message,\n catalogue = defaultCatalogue,\n onAction,\n resolveDataSource,\n surfaceId,\n debounceMs = 300,\n className,\n}: A2UIRendererProps) {\n const fold = React.useMemo(() => foldMessages(message), [message]);\n\n // Local data model per surface, seeded from the folded one. Inputs write here\n // so a bound value updates as the user types; a new payload replaces it,\n // because the agent is then the authority on what the surface shows.\n const [models, setModels] = React.useState<Record<string, Record<string, unknown>>>(() =>\n seedModels(fold.surfaces),\n );\n const seenFold = React.useRef(fold);\n if (seenFold.current !== fold) {\n seenFold.current = fold;\n setModels(seedModels(fold.surfaces));\n }\n\n const resolve = React.useCallback(\n (sourceId: string) => resolveDataSource?.(sourceId),\n [resolveDataSource],\n );\n\n const surfaces = surfaceId\n ? fold.surfaces.filter((surface) => surface.id === surfaceId)\n : fold.surfaces;\n\n const missingSurface = Boolean(surfaceId) && surfaces.length === 0 && fold.surfaces.length > 0;\n\n return (\n <div data-slot=\"a2ui-renderer\" className={cn(\"flex min-w-0 flex-col gap-3\", className)}>\n {fold.errors.length > 0 ? (\n <A2UIErrorCard\n title=\"Malformed A2UI payload\"\n detail={fold.errors.slice(0, 5).join(\" \")}\n />\n ) : null}\n {missingSurface ? (\n <A2UIErrorCard\n title=\"Unknown surface\"\n detail={`No surface \"${surfaceId}\" in this payload.`}\n />\n ) : null}\n {surfaces.map((surface) => (\n <A2UISurfaceView\n key={surface.id}\n surface={surface}\n catalogue={catalogue}\n model={models[surface.id] ?? surface.dataModel}\n setModel={(updater) =>\n setModels((current) => ({\n ...current,\n [surface.id]: updater(current[surface.id] ?? surface.dataModel),\n }))\n }\n onAction={onAction}\n resolveDataSource={resolve}\n debounceMs={debounceMs}\n />\n ))}\n </div>\n );\n}\n\nfunction seedModels(surfaces: readonly A2UISurface[]): Record<string, Record<string, unknown>> {\n const models: Record<string, Record<string, unknown>> = {};\n for (const surface of surfaces) {\n models[surface.id] = surface.dataModel;\n }\n return models;\n}\n\nfunction A2UISurfaceView({\n surface,\n catalogue,\n model,\n setModel,\n onAction,\n resolveDataSource,\n debounceMs,\n}: {\n surface: A2UISurface;\n catalogue: A2UICatalogue;\n model: Record<string, unknown>;\n setModel: (updater: (model: Record<string, unknown>) => Record<string, unknown>) => void;\n onAction: ((action: A2UIAction) => void) | undefined;\n resolveDataSource: (sourceId: string) => DataSource<A2UIRow> | undefined;\n debounceMs: number;\n}) {\n const context: NodeContext = {\n surface,\n catalogue,\n model,\n setModel,\n onAction,\n resolveDataSource,\n debounceMs,\n };\n\n if (!surface.root) {\n return (\n <div data-slot=\"a2ui-surface\" data-surface-id={surface.id}>\n <A2UIErrorCard\n title=\"Empty A2UI surface\"\n detail={`Surface \"${surface.id}\" has no root component. Send updateComponents with a component whose id is \"root\", or name one in createSurface.`}\n />\n </div>\n );\n }\n\n return (\n <div data-slot=\"a2ui-surface\" data-surface-id={surface.id} className=\"flex min-w-0 flex-col\">\n <A2UINode context={context} id={surface.root} contextPath=\"/\" ancestors={[]} depth={0} />\n </div>\n );\n}\n\nfunction A2UINode({\n context,\n id,\n contextPath,\n ancestors,\n depth,\n}: {\n context: NodeContext;\n id: string;\n contextPath: string;\n ancestors: readonly string[];\n depth: number;\n}) {\n const spec = context.surface.components.get(id);\n\n if (!spec) {\n return <A2UIErrorCard title=\"Unknown component id\" detail={`No component \"${id}\" in this surface.`} />;\n }\n if (ancestors.includes(id)) {\n return (\n <A2UIErrorCard\n title=\"Circular component reference\"\n detail={`\"${id}\" is already an ancestor of itself: ${[...ancestors, id].join(\" → \")}.`}\n componentId={id}\n />\n );\n }\n if (depth > MAX_DEPTH) {\n return (\n <A2UIErrorCard\n title=\"Component tree too deep\"\n detail={`More than ${MAX_DEPTH} levels below the root.`}\n componentId={id}\n />\n );\n }\n\n const declaration = readComponent(spec);\n if (!declaration) {\n return (\n <A2UIErrorCard\n title=\"Component has no type\"\n detail=\"Expected `component` to be a catalogue name, or an object keyed by one.\"\n componentId={id}\n />\n );\n }\n\n const entry = context.catalogue[declaration.name];\n if (!entry) {\n return (\n <A2UIErrorCard\n title={`Unknown component \"${declaration.name}\"`}\n detail={`The catalogue has: ${Object.keys(context.catalogue).sort().join(\", \")}.`}\n componentId={id}\n />\n );\n }\n\n // Resolve bindings first, then normalise actions, then validate. A view\n // therefore only ever sees values that passed the entry's schema.\n const raw = declaration.properties;\n const bindings: Record<string, string> = {};\n const resolved: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (key === \"children\") {\n continue;\n }\n if (isDataBinding(value)) {\n bindings[key] = resolvePointer(value.path, contextPath);\n }\n const next = resolveValue(value, context.model, contextPath);\n resolved[key] = key.startsWith(\"on\") ? readAction(next) : next;\n }\n\n const parsed = entry.props.safeParse(resolved);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .slice(0, 4)\n .map((issue) => `${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"; \");\n return (\n <A2UIErrorCard\n title={`Invalid props for ${declaration.name}`}\n detail={issues}\n componentId={id}\n />\n );\n }\n\n const node: A2UINodeInfo = {\n surfaceId: context.surface.id,\n componentId: id,\n dataContextPath: contextPath,\n };\n\n const children =\n entry.children === \"many\"\n ? renderChildren(context, spec, raw, contextPath, [...ancestors, id], depth)\n : [];\n\n const emit = (\n action: A2UIResolvedAction | undefined,\n fallbackName: string,\n payload?: Record<string, unknown>,\n ) => {\n context.onAction?.({\n surfaceId: context.surface.id,\n componentId: id,\n name: action?.name ?? fallbackName,\n payload: { ...(action?.context ?? {}), ...(payload ?? {}) },\n });\n };\n\n const writeBack = (property: string, value: unknown) => {\n const pointer = bindings[property];\n if (!pointer) {\n return;\n }\n context.setModel((model) => setAtPointer(model, pointer, value));\n };\n\n const View = entry.view as React.FC<{\n props: unknown;\n node: A2UINodeInfo;\n children: React.ReactNode[];\n dataModel: Record<string, unknown>;\n emit: typeof emit;\n writeBack: typeof writeBack;\n resolveDataSource: (sourceId: string) => DataSource<A2UIRow> | undefined;\n debounceMs: number;\n }>;\n\n return (\n <View\n props={parsed.data}\n node={node}\n dataModel={context.model}\n emit={emit}\n writeBack={writeBack}\n resolveDataSource={context.resolveDataSource}\n debounceMs={context.debounceMs}\n >\n {children}\n </View>\n );\n}\n\n/**\n * Render a component's children.\n *\n * An explicit list renders each id once. A template renders the referenced\n * component once per item in a bound array, each with its own data context, so\n * an agent describes a row of a table or a list item once instead of repeating\n * it per item.\n */\nfunction renderChildren(\n context: NodeContext,\n spec: A2UIComponentSpec,\n properties: Record<string, unknown>,\n contextPath: string,\n ancestors: readonly string[],\n depth: number,\n): React.ReactNode[] {\n const children = readChildren(spec, properties);\n if (children.kind === \"none\") {\n return [];\n }\n if (children.kind === \"list\") {\n return children.ids.map((childId) => (\n <A2UINode\n key={childId}\n context={context}\n id={childId}\n contextPath={contextPath}\n ancestors={ancestors}\n depth={depth + 1}\n />\n ));\n }\n const pointer = resolvePointer(children.path, contextPath);\n const items = resolveValue({ path: children.path }, context.model, contextPath);\n if (!Array.isArray(items)) {\n return [\n <A2UIErrorCard\n key=\"template-error\"\n title=\"Template list is not an array\"\n detail={`\"${pointer}\" does not resolve to an array in the data model.`}\n />,\n ];\n }\n return items.map((_item, index) => (\n <A2UINode\n key={`${children.componentId}:${index}`}\n context={context}\n id={children.componentId}\n contextPath={`${pointer === \"/\" ? \"\" : pointer}/${index}`}\n ancestors={ancestors}\n depth={depth + 1}\n />\n ));\n}\n\nexport { A2UI_DEFAULT_SURFACE_ID };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { A2UIAction } from "./message.js";
|
|
3
|
+
import "../components/chart/types.js";
|
|
4
|
+
import { DataSource } from "../components/data-table/types.js";
|
|
5
|
+
import "../components/data-table/index.js";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
//#region src/a2ui/views.d.ts
|
|
8
|
+
/** A row in an agent-drawn table. Every value is opaque until a column reads it. */
|
|
9
|
+
export type A2UIRow = Record<string, unknown>;
|
|
10
|
+
/** Where a node sits, carried into every action the view emits. */
|
|
11
|
+
export interface A2UINodeInfo {
|
|
12
|
+
surfaceId: string;
|
|
13
|
+
componentId: string;
|
|
14
|
+
/** JSON pointer this node's relative bindings resolve against. */
|
|
15
|
+
dataContextPath: string;
|
|
16
|
+
}
|
|
17
|
+
/** A normalised action attached to an interactive property. */
|
|
18
|
+
export interface A2UIResolvedAction {
|
|
19
|
+
name: string;
|
|
20
|
+
context?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/** What every view receives. */
|
|
23
|
+
export interface A2UIViewProps<P> {
|
|
24
|
+
props: P;
|
|
25
|
+
node: A2UINodeInfo;
|
|
26
|
+
/** Already-rendered child nodes, in the order the component listed them. */
|
|
27
|
+
children: React.ReactNode[];
|
|
28
|
+
/** The surface data model, for actions that report the whole form. */
|
|
29
|
+
dataModel: Record<string, unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* Send an action. `action` is what the agent attached to the property; when
|
|
32
|
+
* it is absent the event still fires under `fallbackName` so a host can
|
|
33
|
+
* observe interactions the agent did not ask for.
|
|
34
|
+
*/
|
|
35
|
+
emit: (action: A2UIResolvedAction | undefined, fallbackName: string, payload?: Record<string, unknown>) => void;
|
|
36
|
+
/** Write a value back to the data model where this prop was bound. No-op for a literal. */
|
|
37
|
+
writeBack: (property: string, value: unknown) => void;
|
|
38
|
+
/** Resolve a `{ kind: "server", sourceId }` handle into a real data source. */
|
|
39
|
+
resolveDataSource: (sourceId: string) => DataSource<A2UIRow> | undefined;
|
|
40
|
+
/** Debounce applied to continuous inputs before they become actions. */
|
|
41
|
+
debounceMs: number;
|
|
42
|
+
}
|
|
43
|
+
export type A2UIView<P> = React.FC<A2UIViewProps<P>>;
|
|
44
|
+
export interface A2UIColumn {
|
|
45
|
+
id: string;
|
|
46
|
+
label?: string;
|
|
47
|
+
align?: "start" | "center" | "end";
|
|
48
|
+
filter?: "faceted" | "text";
|
|
49
|
+
width?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Where a table's rows come from.
|
|
53
|
+
*
|
|
54
|
+
* `client` carries the rows inline, which suits a short result an agent
|
|
55
|
+
* already has. `server` carries a handle instead: the agent obtains a
|
|
56
|
+
* `sourceId` from a tool and the host resolves it through
|
|
57
|
+
* `resolveDataSource`, so search, sort and paging run on the backend and the
|
|
58
|
+
* agent never has to put ten thousand rows in a message.
|
|
59
|
+
*/
|
|
60
|
+
export type A2UITableSource = {
|
|
61
|
+
kind: "client";
|
|
62
|
+
rows: A2UIRow[];
|
|
63
|
+
} | {
|
|
64
|
+
kind: "server";
|
|
65
|
+
sourceId: string;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* What the renderer draws instead of a component it cannot draw.
|
|
69
|
+
*
|
|
70
|
+
* Never raw markup and never the offending payload as HTML: the detail is set
|
|
71
|
+
* as text, so a malformed message cannot inject anything. This is the
|
|
72
|
+
* "fallback: an error card on malformed payloads" of `05-agent-ui.md`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function A2UIErrorCard({ title, detail, componentId }: {
|
|
75
|
+
title: string;
|
|
76
|
+
detail?: string;
|
|
77
|
+
componentId?: string;
|
|
78
|
+
}): React.JSX.Element;
|
|
79
|
+
//#endregion
|
|
80
|
+
//# sourceMappingURL=views.d.ts.map
|