@adia-ai/a2ui 0.8.37

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +1073 -0
  2. package/README.md +99 -0
  3. package/a2ui.schema.d.ts +192 -0
  4. package/controllers/accordion.js +73 -0
  5. package/controllers/base.js +68 -0
  6. package/controllers/data-stream.js +281 -0
  7. package/controllers/form.js +81 -0
  8. package/controllers/index.js +6 -0
  9. package/controllers/selection.js +82 -0
  10. package/controllers/state-machine.js +135 -0
  11. package/controllers/toggle.js +40 -0
  12. package/dockables/action.d.ts +55 -0
  13. package/dockables/action.js +152 -0
  14. package/dockables/base.d.ts +26 -0
  15. package/dockables/base.js +30 -0
  16. package/dockables/controller.d.ts +35 -0
  17. package/dockables/controller.js +97 -0
  18. package/dockables/data-source.d.ts +35 -0
  19. package/dockables/data-source.js +103 -0
  20. package/dockables/index.d.ts +21 -0
  21. package/dockables/index.js +6 -0
  22. package/dockables/lifecycle.d.ts +38 -0
  23. package/dockables/lifecycle.js +84 -0
  24. package/dockables/provider.d.ts +28 -0
  25. package/dockables/provider.js +59 -0
  26. package/index.d.ts +64 -0
  27. package/index.js +54 -0
  28. package/package.json +89 -0
  29. package/prop-apply.d.ts +13 -0
  30. package/prop-apply.js +113 -0
  31. package/registry.d.ts +17 -0
  32. package/registry.js +418 -0
  33. package/renderer.d.ts +67 -0
  34. package/renderer.js +715 -0
  35. package/stream.d.ts +62 -0
  36. package/stream.js +521 -0
  37. package/surface-manifest.d.ts +73 -0
  38. package/surface-manifest.js +294 -0
  39. package/surface.d.ts +72 -0
  40. package/surface.js +222 -0
  41. package/types.d.ts +26 -0
  42. package/validate/CHANGELOG.md +1005 -0
  43. package/validate/README.md +146 -0
  44. package/validate/index.d.ts +4 -0
  45. package/validate/index.js +12 -0
  46. package/validate/validator.d.ts +4 -0
  47. package/validate/validator.js +1232 -0
  48. package/wire-factory.d.ts +15 -0
  49. package/wire-factory.js +134 -0
  50. package/wiring-engine.d.ts +61 -0
  51. package/wiring-engine.js +209 -0
  52. package/wiring-registry.d.ts +80 -0
  53. package/wiring-registry.js +342 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The attribute-vs-property mapping AdiaUI components expect for one
3
+ * already-resolved prop value. Shared by A2UIRenderer and the genui
4
+ * WidgetAdapter (packages/genui/adia-adapter) — see prop-apply.js.
5
+ */
6
+
7
+ /** Kebab-cases `name` for attribute use, except HTML-standard single-token
8
+ * names (autocomplete, tabindex, …), which stay lowercase-unhyphenated. */
9
+ export declare function toAttr(name: string): string;
10
+
11
+ /** Applies one already-resolved prop value to `el` per AdiaUI's
12
+ * attribute-vs-property policy. No diffing, no binding resolution. */
13
+ export declare function applyResolvedProp(el: Element, key: string, value: unknown): void;
package/prop-apply.js ADDED
@@ -0,0 +1,113 @@
1
+ /**
2
+ * prop-apply.js — the attribute-vs-property mapping AdiaUI components expect
3
+ * for ONE already-resolved prop value. Extracted from A2UIRenderer's
4
+ * `#applyProps` (renderer.js) so the same policy is shared, rather than
5
+ * forked, by:
6
+ * - A2UIRenderer (the legacy DOM-string streaming renderer), and
7
+ * - the genui WidgetAdapter (packages/genui/adia-adapter) — its `setProp`
8
+ * receives one resolved value per call, with no diffing to do, so this
9
+ * module is exactly the slice it needs.
10
+ *
11
+ * Policy encoded here (do not duplicate elsewhere — fix it once, here):
12
+ * - `style` (string) → `el.style.cssText`.
13
+ * - JS-property props (data/columns/options/itemRenderer/textContent) →
14
+ * set as a JS property, not an attribute — components read these as
15
+ * arrays/objects, not markup strings. `textContent` on a non-text-bearing
16
+ * tag (a container like card-ui/alert-ui) is redirected to the `text=`
17
+ * attribute instead of `el.textContent = …`, which would wipe slotted +
18
+ * appended children.
19
+ * - A JSON-looking string ('[' / '{' prefixed) destined for a JS-property
20
+ * prop is parsed — corpus templates encode `data`/`columns` as JSON
21
+ * strings; components expect arrays.
22
+ * - boolean → attribute presence (`setAttribute(key, '')` / removeAttribute).
23
+ * - everything else → `setAttribute(toAttr(key), String(value))`.
24
+ */
25
+
26
+ // Props components read as a JS property (array/object), never a markup
27
+ // string — see #JS_PROPS in renderer.js (kept in sync; this IS that set now).
28
+ const JS_PROPS = new Set(['data', 'columns', 'options', 'itemRenderer', 'textContent']);
29
+
30
+ // Tags where `el.textContent = value` is safe — pure text-bearing leaves.
31
+ // On a container, textContent would wipe slotted + appended children.
32
+ const TEXT_TAG_OK = new Set([
33
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
34
+ 'p', 'small', 'span', 'em', 'strong', 'code',
35
+ 'text-ui',
36
+ 'kbd-ui', // "Content via innerHTML", no text= attribute fallback (TKT-0025)
37
+ ]);
38
+
39
+ // HTML-standard single-token attribute names (all-lowercase in the HTML
40
+ // spec) — passed through unchanged rather than naive-kebabbed, which would
41
+ // mangle e.g. autoComplete → "auto-complete" (HTML attr is "autocomplete").
42
+ const HTML_LOWERCASE_ATTRS = new Set([
43
+ 'autocomplete', 'autofocus', 'autocapitalize', 'autocorrect',
44
+ 'inputmode', 'enterkeyhint', 'spellcheck',
45
+ 'maxlength', 'minlength', 'readonly', 'novalidate', 'formnovalidate',
46
+ 'formaction', 'formenctype', 'formmethod', 'formtarget',
47
+ 'multiple', 'pattern', 'placeholder', 'required',
48
+ 'tabindex', 'accesskey',
49
+ 'autoplay', 'autopictureinpicture', 'controls', 'crossorigin',
50
+ 'disablepictureinpicture', 'disableremoteplayback',
51
+ 'loop', 'muted', 'playsinline', 'preload',
52
+ 'srcset', 'srcdoc', 'srclang', 'sizes', 'loading',
53
+ 'decoding', 'fetchpriority', 'ismap', 'usemap',
54
+ 'hreflang', 'referrerpolicy', 'download',
55
+ 'contenteditable', 'contextmenu', 'draggable',
56
+ 'dirname', 'colspan', 'rowspan', 'headers',
57
+ 'allowfullscreen', 'allowpaymentrequest',
58
+ 'itemid', 'itemprop', 'itemref', 'itemscope', 'itemtype',
59
+ 'nomodule', 'nonce',
60
+ ]);
61
+
62
+ /**
63
+ * Kebab-cases a camelCase prop name for attribute use, except for the
64
+ * HTML-standard single-token names above, which stay lowercase-unhyphenated.
65
+ */
66
+ export function toAttr(name) {
67
+ if (HTML_LOWERCASE_ATTRS.has(name.toLowerCase())) return name.toLowerCase();
68
+ return name.replace(/([A-Z])/g, '-$1').toLowerCase();
69
+ }
70
+
71
+ /**
72
+ * Applies one already-resolved prop value to `el` per AdiaUI's
73
+ * attribute-vs-property policy. No diffing, no binding resolution — the
74
+ * caller has already decided this value needs writing.
75
+ */
76
+ export function applyResolvedProp(el, key, value) {
77
+ if (key === 'style' && typeof value === 'string') {
78
+ el.style.cssText = value;
79
+ return;
80
+ }
81
+
82
+ if (JS_PROPS.has(key) && value != null) {
83
+ if (key === 'textContent' && !TEXT_TAG_OK.has(el.localName)) {
84
+ el.setAttribute('text', String(value));
85
+ return;
86
+ }
87
+ let v = value;
88
+ if (typeof v === 'string' && (v.startsWith('[') || v.startsWith('{'))) {
89
+ try { v = JSON.parse(v); } catch { /* keep as string on parse failure */ }
90
+ }
91
+ el[key] = v;
92
+ return;
93
+ }
94
+
95
+ if (typeof value === 'boolean') {
96
+ // toAttr(key) — not the raw camelCase key. Every prior boolean prop
97
+ // through this path (disabled/checked/…) is a single lowercase word,
98
+ // so toAttr is the identity and this was invisible; allowEmpty is the
99
+ // first camelCase boolean, and the raw-key branch wrote
100
+ // `allowempty=""` while segmented-ui observes `allow-empty` — the
101
+ // property never flipped and the connect-time self-select still ran
102
+ // (gh#693 follow-up, caught in review before merge).
103
+ if (value) el.setAttribute(toAttr(key), '');
104
+ else el.removeAttribute(toAttr(key));
105
+ return;
106
+ }
107
+
108
+ if (value != null) {
109
+ el.setAttribute(toAttr(key), String(value));
110
+ } else {
111
+ el.removeAttribute(toAttr(key));
112
+ }
113
+ }
package/registry.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A2UI Registry — maps A2UI type names to AdiaUI custom element tag names.
3
+ */
4
+
5
+ /** The global registry Map from A2UI type name → custom element tag name. */
6
+ export declare const registry: Map<string, string>;
7
+
8
+ /**
9
+ * Resolve an A2UI component type to an AdiaUI tag name.
10
+ * Returns null (not undefined) when the type is unknown.
11
+ */
12
+ export declare function resolveTag(type: string): string | null;
13
+
14
+ /**
15
+ * Register a custom component type mapping.
16
+ */
17
+ export declare function registerType(type: string, tagName: string): void;
package/registry.js ADDED
@@ -0,0 +1,418 @@
1
+ /**
2
+ * A2UI Registry — maps A2UI type names to AdiaUI custom element tag names.
3
+ *
4
+ * Usage:
5
+ * import { registry, resolveTag } from './registry.js';
6
+ * resolveTag('Button') // → 'button-ui'
7
+ * resolveTag('ChoicePicker') // → 'select-ui'
8
+ * resolveTag('Toggle') // → 'switch-ui'
9
+ */
10
+
11
+ export const registry = new Map([
12
+
13
+ // ══════════════════════════════════════════════════════
14
+ // A2UI Protocol Types (standard catalog)
15
+ // ══════════════════════════════════════════════════════
16
+
17
+ // Layout
18
+ ['Row', 'row-ui'],
19
+ ['Column', 'col-ui'],
20
+ ['List', 'list-ui'],
21
+ ['ListItem', 'list-item-ui'],
22
+ ['Grid', 'grid-ui'],
23
+ ['Stack', 'stack-ui'],
24
+ ['Block', 'block-ui'],
25
+
26
+ // Display
27
+ ['Text', 'text-ui'],
28
+ ['Image', 'image-ui'],
29
+ ['Icon', 'icon-ui'],
30
+ ['Divider', 'divider-ui'],
31
+ ['Badge', 'badge-ui'],
32
+ ['Avatar', 'avatar-ui'],
33
+ ['AvatarGroup', 'avatar-group-ui'],
34
+ ['Progress', 'progress-ui'],
35
+ ['ProgressRow', 'progress-row-ui'],
36
+ ['DateRangePicker', 'date-range-picker-ui'],
37
+ ['DatetimePicker', 'datetime-picker-ui'],
38
+ ['CalendarGrid', 'calendar-grid-ui'],
39
+ ['CalendarPicker', 'calendar-picker-ui'],
40
+ ['Combobox', 'combobox-ui'],
41
+ ['Skeleton', 'skeleton-ui'],
42
+ ['Stepper', 'stepper-ui'],
43
+ ['StepperItem', 'stepper-item-ui'],
44
+ ['Tour', 'tour-ui'],
45
+ ['TourStep', 'tour-step-ui'],
46
+ ['IntegrationCard', 'integration-card-ui'],
47
+ ['Code', 'code-ui'],
48
+ ['Stat', 'stat-ui'],
49
+ ['EmptyState', 'empty-state-ui'],
50
+
51
+ // Input
52
+ ['Input', 'input-ui'],
53
+ ['TextField', 'input-ui'],
54
+ ['TextArea', 'textarea-ui'],
55
+ ['Field', 'field-ui'],
56
+ ['CheckBox', 'check-ui'],
57
+ ['Toggle', 'switch-ui'],
58
+ ['Switch', 'switch-ui'],
59
+ ['Slider', 'slider-ui'],
60
+ ['Range', 'range-ui'],
61
+ ['Rating', 'rating-ui'],
62
+ ['ChoicePicker', 'select-ui'],
63
+ ['Select', 'select-ui'],
64
+ ['Radio', 'radio-ui'],
65
+ ['RadioGroup', 'radio-group-ui'],
66
+ ['DateTimeInput', 'calendar-picker-ui'],
67
+ ['CalendarPicker', 'calendar-picker-ui'],
68
+ ['ColorPicker', 'color-picker-ui'],
69
+ // Search deprecated — use Input type="search" prefix="magnifying-glass"
70
+ ['Upload', 'upload-ui'],
71
+ ['OtpInput', 'otp-input-ui'],
72
+
73
+ // Action
74
+ ['Button', 'button-ui'],
75
+
76
+ // System State
77
+ ['LoadingIndicator', 'progress-ui'],
78
+ ['ErrorContainer', 'card-ui'],
79
+
80
+ // Container
81
+ ['Card', 'card-ui'],
82
+ ['Tabs', 'tabs-ui'],
83
+ ['Tab', 'tab-ui'],
84
+ ['Panel', 'pane-ui'],
85
+ ['Pane', 'pane-ui'],
86
+ ['Modal', 'modal-ui'],
87
+ ['Dialog', 'modal-ui'],
88
+ ['Drawer', 'drawer-ui'],
89
+ ['Toast', 'toast-ui'],
90
+ ['AnchorBar', 'anchor-bar-ui'],
91
+ ['Popover', 'popover-ui'],
92
+ ['Accordion', 'accordion-ui'],
93
+ ['AccordionItem', 'accordion-item-ui'],
94
+ ['Alert', 'alert-ui'],
95
+ ['Tooltip', 'tooltip-ui'],
96
+ ['Menu', 'menu-ui'],
97
+
98
+ // Card children (native HTML elements styled by card.css)
99
+ ['Section', 'section'],
100
+ ['Header', 'header'],
101
+ ['Footer', 'footer'],
102
+
103
+ // Agent / Specialized
104
+ ['Stream', 'stream-ui'],
105
+ ['Table', 'table-ui'],
106
+ ['ColDef', 'col-def'], // declarative column definition child of table-ui
107
+ ['Chart', 'chart-ui'],
108
+ ['Embed', 'embed-ui'],
109
+ ['Swiper', 'swiper-ui'],
110
+ ['Slideshow', 'swiper-ui'],
111
+ ['Carousel', 'swiper-ui'],
112
+
113
+ // Navigation
114
+ ['Breadcrumb', 'breadcrumb-ui'],
115
+ ['Link', 'link-ui'],
116
+ ['Anchor', 'link-ui'],
117
+ ['Hyperlink', 'link-ui'],
118
+ ['NavLink', 'link-ui'],
119
+ ['Nav', 'nav-ui'],
120
+ ['NavGroup', 'nav-group-ui'],
121
+ ['NavItem', 'nav-item-ui'],
122
+ ['Noodles', 'noodles-ui'],
123
+ ['Pagination', 'pagination-ui'],
124
+ ['SegmentedControl', 'segmented-ui'],
125
+ ['Segment', 'segment-ui'],
126
+ ['ToggleGroup', 'toggle-group-ui'],
127
+
128
+ // Utility
129
+ ['Command', 'command-ui'],
130
+ ['Kbd', 'kbd-ui'],
131
+ ['Toolbar', 'toolbar-ui'],
132
+ // gh#535 — missing entry made toolbar-group-ui an UNKNOWN tag: the docs
133
+ // transpiler Column-wrapped every group, so the floating bulk-action bar
134
+ // rendered as vertical col-ui stacks on its site route. Catalog already
135
+ // carries ToolbarGroup.
136
+ ['ToolbarGroup', 'toolbar-group-ui'],
137
+ ['Tag', 'tag-ui'],
138
+ ['Timeline', 'timeline-ui'],
139
+ ['TimelineItem', 'timeline-item-ui'],
140
+
141
+ // ══════════════════════════════════════════════════════
142
+ // AgentUI Aliases (backwards compat with -ui tags)
143
+ // ══════════════════════════════════════════════════════
144
+ ['button-ui', 'button-ui'],
145
+ ['card-ui', 'card-ui'],
146
+ ['text-ui', 'text-ui'],
147
+ ['input-ui', 'input-ui'],
148
+ ['text-field-ui', 'input-ui'],
149
+ ['select-ui', 'select-ui'],
150
+ ['toggle-ui', 'switch-ui'],
151
+ ['check-ui', 'check-ui'],
152
+ ['slider-ui', 'slider-ui'],
153
+ ['badge-ui', 'badge-ui'],
154
+ ['avatar-ui', 'avatar-ui'],
155
+ ['icon-ui', 'icon-ui'],
156
+ ['image-ui', 'image-ui'],
157
+ ['divider-ui', 'divider-ui'],
158
+ ['progress-ui', 'progress-ui'],
159
+ ['skeleton-ui', 'skeleton-ui'],
160
+ ['tabs-ui', 'tabs-ui'],
161
+ ['tab-ui', 'tab-ui'],
162
+ ['modal-ui', 'modal-ui'],
163
+ ['dialog-ui', 'modal-ui'],
164
+ ['drawer-ui', 'drawer-ui'],
165
+ ['toast-ui', 'toast-ui'],
166
+ ['popover-ui', 'popover-ui'],
167
+ ['panel-ui', 'pane-ui'],
168
+ ['accordion-ui', 'accordion-ui'],
169
+ ['alert-ui', 'alert-ui'],
170
+ ['tooltip-ui', 'tooltip-ui'],
171
+ ['menu-ui', 'menu-ui'],
172
+ ['table-ui', 'table-ui'],
173
+ ['chart-ui', 'chart-ui'],
174
+ ['code-ui', 'code-ui'],
175
+ ['textarea-ui', 'textarea-ui'],
176
+ ['radio-ui', 'radio-ui'],
177
+ ['tag-ui', 'tag-ui'],
178
+ ['search-ui', 'search-ui'],
179
+ ['upload-ui', 'upload-ui'],
180
+ ['breadcrumb-ui', 'breadcrumb-ui'],
181
+ ['link-ui', 'link-ui'],
182
+ ['nav-ui', 'nav-ui'],
183
+ ['noodles-ui', 'noodles-ui'],
184
+ ['pagination-ui', 'pagination-ui'],
185
+ ['segmented-control-ui', 'segmented-ui'],
186
+ ['segment-ui', 'segment-ui'],
187
+ ['command-ui', 'command-ui'],
188
+ ['calendar-picker-ui', 'calendar-picker-ui'],
189
+ ['color-picker-ui', 'color-picker-ui'],
190
+ ['kbd-ui', 'kbd-ui'],
191
+ ['toolbar-ui', 'toolbar-ui'],
192
+ ['otp-input-ui', 'otp-input-ui'],
193
+ ['embed-ui', 'embed-ui'],
194
+ ['stream-ui', 'stream-ui'],
195
+ ['row-ui', 'row-ui'],
196
+ ['col-ui', 'col-ui'],
197
+ ['grid-ui', 'grid-ui'],
198
+ ['stack-ui', 'stack-ui'],
199
+ ['block-ui', 'block-ui'],
200
+ ['list-ui', 'list-ui'],
201
+ ['range-ui', 'range-ui'],
202
+ ['datetime-ui', 'calendar-picker-ui'],
203
+ ['timeline-ui', 'timeline-ui'],
204
+ ['timeline-item-ui', 'timeline-item-ui'],
205
+ ['avatar-group-ui', 'avatar-group-ui'],
206
+
207
+ // Aliases (alternate names)
208
+ ['Keyboard', 'kbd-ui'],
209
+ ['DatePicker', 'calendar-picker-ui'],
210
+ ['CommandPalette', 'command-ui'],
211
+ ['FormContainer', 'form'], // §45 — transpiler maps <form> → FormContainer; no form-ui component exists, so render as native <form>
212
+ ['Sidebar', 'admin-sidebar'], // §48 — transpiler maps <aside> → Sidebar; routed to the AdminSidebar web-module (packages/web-modules/shell/admin-sidebar/). Per-user directive in §49: prefer admin-sidebar over native <aside> for sidebar affordances.
213
+ ['Segmented', 'segmented-ui'],
214
+ ['OTP', 'otp-input-ui'],
215
+
216
+ // Missing PascalCase entries discovered by verify:corpus (§39, 2026-05-12).
217
+ // Composition corpus used these names; registry didn't map them so the
218
+ // renderer would have silently dropped these components.
219
+ ['Textarea', 'textarea-ui'], // case alias for TextArea
220
+ ['RichText', 'richtext-ui'],
221
+ ['Richtext', 'richtext-ui'], // case alias
222
+ ['DescriptionList', 'description-list-ui'],
223
+ ['ActionItem', 'action-item-ui'],
224
+ ['ActionList', 'action-list-ui'],
225
+ ['Inspector', 'inspector-ui'],
226
+ ['Heatmap', 'heatmap-ui'],
227
+ // §176 (v0.5.5): removed legacy `['Chat', 'chat-ui']` alias. Renamed
228
+ // to chat-thread-ui in pre-0.2.0; zero usage in current codebase
229
+ // (verified with `grep -rE '<chat-ui|\\bChat\\b\\s*\\(' packages apps`
230
+ // returning no real callers). Was a §175 baseline orphan; removing
231
+ // the registry entry closes it cleanly.
232
+ ['ChatThread', 'chat-thread'], // §49 — re-routed to the chat web-module (was: chat-thread-ui primitive). The module owns scroll-to-bottom + streaming; primitive remains accessible via bare `chat-thread-ui` tag.
233
+ ['ChatInput', 'chat-input-ui'],
234
+ ['OptionCard', 'option-card-ui'],
235
+ ['Option', 'option-card-ui'], // bare Option → option-card-ui
236
+
237
+ // §49 — web-module catalog mappings (packages/web-modules/<cluster>/).
238
+ // These are module-tier components that compose primitives into full
239
+ // surface affordances (page shells, sidebars, chat surfaces, editor
240
+ // surfaces, theme panel). Without these entries, A2UI corpus records
241
+ // emitting any of them produce unknown-component criticals (same
242
+ // pattern caught reactively for FormContainer §45 + Sidebar §48).
243
+ // Discovered via a transpiler-vs-registry audit across §49.
244
+
245
+ // Admin shell cluster — chrome surfaces for SaaS admin/dashboard surfaces
246
+ ['AdminCommand', 'admin-command'],
247
+ ['AdminContent', 'admin-content'],
248
+ ['AdminPage', 'admin-page'],
249
+ ['AdminPageBody', 'admin-page-body'],
250
+ ['AdminPageHeader', 'admin-page-header'],
251
+ ['AdminScroll', 'admin-scroll'],
252
+ ['AdminShell', 'admin-shell'],
253
+ ['AdminSidebar', 'admin-sidebar'], // canonical PascalCase mapping; the Sidebar alias above resolves through this
254
+ ['AdminStatusbar', 'admin-statusbar'],
255
+ ['AdminTopbar', 'admin-topbar'],
256
+
257
+ // Chat cluster — LLM-streaming conversation surfaces
258
+ ['ChatComposer', 'chat-composer'],
259
+ ['ChatEmpty', 'chat-empty'],
260
+ ['ChatHeader', 'chat-header'],
261
+ ['ChatShell', 'chat-shell'],
262
+ ['ChatSidebar', 'chat-sidebar'],
263
+ ['ChatStatus', 'chat-status'],
264
+
265
+ // Editor cluster — A2UI canvas editor surfaces
266
+ ['EditorCanvas', 'editor-canvas'],
267
+ ['EditorCanvasEmpty', 'editor-canvas-empty'],
268
+ ['EditorShell', 'editor-shell'],
269
+ ['EditorSidebar', 'editor-sidebar'],
270
+ ['EditorStatusbar', 'editor-statusbar'],
271
+ ['EditorToolbar', 'editor-toolbar'],
272
+
273
+ // Runtime / simple / theme — singleton surfaces
274
+ ['GenRoot', 'gen-root'],
275
+ ['SimpleContent', 'simple-content'],
276
+ ['SimpleHero', 'simple-hero'],
277
+ ['SimpleShell', 'simple-shell'],
278
+ ['ThemePanel', 'theme-panel'],
279
+
280
+ // gh#645 — 50 catalog types with NO registry mapping, found by the
281
+ // patient-visit browser probe: `resolveTag()` returned null for every
282
+ // one below even though `effectiveCatalog()` (derived from all 138
283
+ // sidecars) already knew the type, so `createAdiaAdapter` rendered
284
+ // literal `[unknown: X]` text instead of the real element. Each tag
285
+ // is read straight off the component's own `.a2ui.json` sidecar
286
+ // (`x-adiaui.tag`), not guessed from the type name — see
287
+ // `check:genui-catalog`'s new `resolveTag` assertion, which now fails
288
+ // the build the moment a catalog type ships without a registry entry.
289
+ ['AdiaMark', 'adia-mark-ui'],
290
+ ['AdiaWordmark', 'adia-wordmark-ui'],
291
+ ['AgentArtifact', 'agent-artifact-ui'],
292
+ ['AgentFeedbackBar', 'agent-feedback-bar-ui'],
293
+ ['AgentQuestions', 'agent-questions-ui'],
294
+ ['AgentReasoning', 'agent-reasoning-ui'],
295
+ ['AgentSuggestions', 'agent-suggestions-ui'],
296
+ ['AgentTrace', 'agent-trace-ui'],
297
+ ['Aside', 'aside-ui'],
298
+ ['Blockquote', 'blockquote-ui'],
299
+ ['Canvas', 'canvas-ui'],
300
+ ['ChartLegend', 'chart-legend-ui'],
301
+ ['ColorInput', 'color-input-ui'],
302
+ ['ContextMenu', 'context-menu-ui'],
303
+ ['DemoToggle', 'demo-toggle-ui'],
304
+ ['DisplayField', 'display-field-ui'],
305
+ ['Feed', 'feed-ui'],
306
+ ['FeedItem', 'feed-item-ui'],
307
+ ['Fields', 'fields-ui'],
308
+ ['Frame', 'frame-ui'],
309
+ ['InlineEdit', 'inline-edit-ui'],
310
+ ['InlineMessage', 'inline-message-ui'],
311
+ ['ListWindow', 'list-window-ui'],
312
+ ['LoadingOverlay', 'loading-overlay-ui'],
313
+ ['Mark', 'mark-ui'],
314
+ ['MenuDivider', 'menu-divider-ui'],
315
+ ['MenuItem', 'menu-item-ui'],
316
+ ['MenuLabel', 'menu-label-ui'],
317
+ ['NumberFormat', 'number-format-ui'],
318
+ ['Page', 'page-ui'],
319
+ ['PasswordStrength', 'password-strength-ui'],
320
+ ['PipelineStatus', 'pipeline-status-ui'],
321
+ ['Preview', 'preview-ui'],
322
+ ['QRCode', 'qr-code-ui'],
323
+ ['RelativeTime', 'relative-time-ui'],
324
+ ['Search', 'search-ui'],
325
+ ['SkipNav', 'skip-nav-ui'],
326
+ ['Spinner', 'spinner-ui'],
327
+ ['StepProgress', 'step-progress-ui'],
328
+ ['Swatch', 'swatch-ui'],
329
+ // sidecar directory is `toc/toc.a2ui.json`; catalog title is TableOfContents
330
+ // but the component's own tag is the shorter `toc-ui` (x-adiaui.tag) — not
331
+ // the naive `table-of-contents-ui` kebab expansion of the type name.
332
+ ['TableOfContents', 'toc-ui'],
333
+ ['TableToolbar', 'table-toolbar-ui'],
334
+ ['TagsInput', 'tags-input-ui'],
335
+ // No `-ui` suffix — ThemeProvider is infra (a constructable-stylesheet
336
+ // provider), registered the same bare-tag way as the other singleton
337
+ // surfaces above (GenRoot, SimpleShell, ThemePanel).
338
+ ['ThemeProvider', 'theme-provider'],
339
+ ['TimePicker', 'time-picker-ui'],
340
+ ['ToggleOption', 'toggle-option-ui'],
341
+ ['ToggleScheme', 'toggle-scheme-ui'],
342
+ ['Tree', 'tree-ui'],
343
+ ['TreeItem', 'tree-item-ui'],
344
+ ['VisuallyHidden', 'visually-hidden-ui'],
345
+
346
+ // gh#848 — 18 shipping web-module composites that ship a full contract
347
+ // (`<c>.yaml` + derived `<c>.a2ui.json` + `customElements.define`) but
348
+ // never got a registry entry, so `reverseRegistry` could not resolve
349
+ // their tags and the docs transpiler's "6. Unknown" fallback converted
350
+ // each one to an EMPTY Column — 24 site pages rendered a blank shell
351
+ // where the component belongs (surfaced by gh#847's loud-degrade
352
+ // instrumentation). Every type name below is the component's own
353
+ // `component:` field and every tag its own `tag:` field, read from the
354
+ // yaml SoT — never kebab-guessed from the type name (gh#645's rule;
355
+ // `embed-shell` and `admin-entity-item` both break the naive
356
+ // kebab + "-ui" pattern, and `embed-shell` declares `component: AppShell`).
357
+ ['AdminEntityItem', 'admin-entity-item'],
358
+ ['AdminRoster', 'admin-roster-ui'],
359
+ ['AdminSettings', 'admin-settings-ui'],
360
+ ['AgentAdmin', 'agent-admin-ui'],
361
+ ['AppShell', 'embed-shell'],
362
+ ['BillingOverview', 'billing-overview-ui'],
363
+ ['ConfirmDialog', 'confirm-dialog-ui'],
364
+ ['DashboardLayout', 'dashboard-layout-ui'],
365
+ ['DateRangeSelector', 'date-range-selector-ui'],
366
+ ['FormPopover', 'form-popover-ui'],
367
+ ['IntegrationsPage', 'integrations-page-ui'],
368
+ ['InvoiceDetail', 'invoice-detail-ui'],
369
+ ['InvoiceHistory', 'invoice-history-ui'],
370
+ ['NotificationPreferences', 'notification-preferences-ui'],
371
+ ['OnboardingChecklist', 'onboarding-checklist-ui'],
372
+ ['PaymentMethodForm', 'payment-method-form-ui'],
373
+ ['PaymentMethodList', 'payment-method-list-ui'],
374
+ ['PlanPicker', 'plan-picker-ui'],
375
+
376
+ // gh#848 — the same gap for two components whose PascalCase name is
377
+ // already claimed by a DIFFERENT element, so they get the registry's
378
+ // established bare-tag alias shape instead (`['row-ui','row-ui']`, …).
379
+ // derive-genui-catalog.mjs:207 skips name===tag pairs as canonical-name
380
+ // candidates, so neither entry perturbs the derived catalog.
381
+ // chat-thread-ui — `ChatThread` routes to the chat WEB-MODULE
382
+ // (`chat-thread`) since §49; that entry's own comment already names
383
+ // the bare tag as the primitive's access path. This makes it real.
384
+ // section-ui — `Section` must keep resolving to the NATIVE `section`:
385
+ // card.css scopes `& > section` and carries no `section-ui` rule at
386
+ // all, so retargeting the type would silently unstyle every
387
+ // converted card body. `section-ui` is the page/sidebar-tier stub
388
+ // (page.css:70-84, admin-shell.sidebar.css:139) and needs its own
389
+ // handle. The Section/section-ui double-booking itself is a catalog
390
+ // design call, recorded in gh#848 — not resolved here.
391
+ ['chat-thread-ui', 'chat-thread-ui'],
392
+ ['section-ui', 'section-ui'],
393
+
394
+ // gh#848 — description-list children. `<description-list-ui>` renders a
395
+ // native `<dl>` and its contract (description-list.yaml `slots`) is
396
+ // "consumer passes <dt>/<dd> children inline", so the pair are native
397
+ // elements, registered the same way as the `Section`/`Header`/`Footer`
398
+ // card children above. Without them the transpiled description list is
399
+ // a `dl` full of Columns and the term/detail grid collapses.
400
+ ['DescriptionTerm', 'dt'],
401
+ ['DescriptionDetail', 'dd'],
402
+ ]);
403
+
404
+ /**
405
+ * Resolve an A2UI component type to a AdiaUI tag name.
406
+ * @param {string} type — A2UI type name or AgentUI tag
407
+ * @returns {string|null} — AdiaUI tag name or null
408
+ */
409
+ export function resolveTag(type) {
410
+ return registry.get(type) || null;
411
+ }
412
+
413
+ /**
414
+ * Register a custom component type.
415
+ */
416
+ export function registerType(type, tagName) {
417
+ registry.set(type, tagName);
418
+ }
package/renderer.d.ts ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * A2UI Renderer — processes A2UI messages and renders AdiaUI components into the DOM.
3
+ */
4
+
5
+ import type { A2UIMessage } from './index.js';
6
+
7
+ /** Options for A2UIRenderer constructor. */
8
+ export interface A2UIRendererOptions {
9
+ /** Enable RAF-batched rendering. Default: false. */
10
+ batch?: boolean;
11
+ }
12
+
13
+ /** Surface state returned by getSurface(). */
14
+ export interface SurfaceState {
15
+ root: HTMLElement;
16
+ rootId: string;
17
+ elements: Map<string, HTMLElement>;
18
+ dataModel: Record<string, unknown>;
19
+ bindings: Map<string, unknown>;
20
+ }
21
+
22
+ export declare class A2UIRenderer {
23
+ /**
24
+ * @param container - Root DOM element to render surfaces into.
25
+ * @param reg - Optional custom registry (defaults to the built-in registry Map).
26
+ * @param options - Renderer options.
27
+ */
28
+ constructor(
29
+ container: HTMLElement,
30
+ reg?: Map<string, string>,
31
+ options?: A2UIRendererOptions,
32
+ );
33
+
34
+ /**
35
+ * Process a single A2UI message, rendering it into the container.
36
+ * In batching mode messages are queued and flushed on the next animation frame.
37
+ */
38
+ process(message: A2UIMessage | Record<string, unknown>): void;
39
+
40
+ /**
41
+ * Consume an async iterable of messages, processing each in turn.
42
+ */
43
+ processStream(stream: AsyncIterable<A2UIMessage | Record<string, unknown>>): Promise<void>;
44
+
45
+ /**
46
+ * Get the internal surface state for a surface ID (useful for testing).
47
+ */
48
+ getSurface(id: string): SurfaceState | undefined;
49
+
50
+ /**
51
+ * Get a DOM element by component ID across all surfaces.
52
+ */
53
+ getElement(id: string): HTMLElement | undefined;
54
+
55
+ /**
56
+ * IDs of all active surfaces.
57
+ */
58
+ readonly surfaces: string[];
59
+
60
+ /**
61
+ * Remove all rendered surfaces and cancel any pending frame.
62
+ */
63
+ reset(): void;
64
+
65
+ /** Enable or disable RAF batching at runtime. */
66
+ batching: boolean;
67
+ }