-
Notifications
You must be signed in to change notification settings - Fork 1.2k
docs: add Lit custom component registration guide for v0.9 and v0.8 #1428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d32de4d
5219e15
342a6d9
f235be9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -148,7 +148,11 @@ Keep these key points in mind when implementing components: | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ## 3. Registering with the Renderer (Client) | ||||||||||||||||||||||||||||||||||||||||||||||
| ## 3. Registering with the Renderers (Client) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| Register the component with your renderer so that A2UI can instantiate it when the agent sends a payload referencing it. The steps differ by renderer. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ### Angular renderer | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| Once the component is implemented, register it in your client catalog. This maps the component name (used by agents) to the implementation class. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -179,6 +183,75 @@ Key points for registration: | |||||||||||||||||||||||||||||||||||||||||||||
| - **Lazy Loading**: Use `import()` to lazy-load the component code. | ||||||||||||||||||||||||||||||||||||||||||||||
| - **Input Bindings**: Use `inputBinding` to map properties from the schema to Angular inputs. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ### Lit v0.9 (recommended) | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| With `@a2ui/lit/v0_9`, catalog registration is handled at the protocol level. Define a `Catalog` object with your components and pass it to the `MessageProcessor`. When the agent sends a `createSurface` message with a matching `catalogId`, the processor automatically resolves and binds your catalog — no client-side flags required. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||
| import {z} from 'zod'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import {Catalog, MessageProcessor} from '@a2ui/web_core/v0_9'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import {basicCatalog} from '@a2ui/lit/v0_9'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import type {LitComponentApi} from '@a2ui/lit/v0_9'; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // 1. Define your component's API using a Zod schema | ||||||||||||||||||||||||||||||||||||||||||||||
| const MyChartApi = { | ||||||||||||||||||||||||||||||||||||||||||||||
| name: 'MyChart', | ||||||||||||||||||||||||||||||||||||||||||||||
| tagName: 'my-chart', // your custom element tag | ||||||||||||||||||||||||||||||||||||||||||||||
| schema: z.object({ | ||||||||||||||||||||||||||||||||||||||||||||||
| title: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||||||
| data: z.array(z.object({label: z.string(), value: z.number()})), | ||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||
| } satisfies LitComponentApi; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // 2. Create a named catalog containing your component(s) | ||||||||||||||||||||||||||||||||||||||||||||||
| const myCatalog = new Catalog<LitComponentApi>( | ||||||||||||||||||||||||||||||||||||||||||||||
| 'mycompany.com:my-catalog', // must match what the agent sends in createSurface.catalogId | ||||||||||||||||||||||||||||||||||||||||||||||
| [MyChartApi], | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // 3. Register it with the MessageProcessor alongside any other catalogs you support | ||||||||||||||||||||||||||||||||||||||||||||||
| const processor = new MessageProcessor<LitComponentApi>([basicCatalog, myCatalog]); | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+212
to
+213
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a "4." illustrating how the "processor" is used? I think that's the final piece of the puzzle. |
||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| The agent then selects your catalog by referencing its ID in the `createSurface` message: | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ```json | ||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||
| "version": "v0.9", | ||||||||||||||||||||||||||||||||||||||||||||||
| "createSurface": { | ||||||||||||||||||||||||||||||||||||||||||||||
| "surfaceId": "main", | ||||||||||||||||||||||||||||||||||||||||||||||
| "catalogId": "mycompany.com:my-catalog" | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| The `A2uiSurface` element in v0.9 receives a fully-resolved `SurfaceModel` (with catalog already bound), so custom components render automatically alongside standard ones. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ### Lit v0.8 (legacy) | ||||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm tempted to use the "tabs" widget that we have to hide the Lit v0.8 behind a tab, like we do here: A2UI/docs/concepts/overview.md Lines 29 to 50 in 0e03757
That way the page doesn't grow too tall, and you only see the things about the framework you care about; what do you think? |
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| When using the `@a2ui/lit` renderer with the v0.8 protocol, register your custom components via the `componentRegistry`, then opt in on the `<a2ui-surface>` element by setting `enableCustomElements = true`. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||
| import {v0_8 as a2uiModule} from '@a2ui/lit'; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Register custom components in the component registry | ||||||||||||||||||||||||||||||||||||||||||||||
| // MyChartElement is your Lit component class (extends LitElement) | ||||||||||||||||||||||||||||||||||||||||||||||
| a2uiModule.componentRegistry.register('MyChart', MyChartElement); | ||||||||||||||||||||||||||||||||||||||||||||||
|
shahabl marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| Then set `enableCustomElements = true` on the surface element **before** assigning `surface` and `processor`, so the flag is active on the first render pass: | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||
| const surfaceElement = document.querySelector('a2ui-surface'); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| surfaceElement.enableCustomElements = true; // must come first | ||||||||||||||||||||||||||||||||||||||||||||||
| surfaceElement.surfaceId = 'main'; | ||||||||||||||||||||||||||||||||||||||||||||||
| surfaceElement.surface = surface; // the SurfaceModel instance | ||||||||||||||||||||||||||||||||||||||||||||||
| surfaceElement.processor = processor; // the A2uiMessageProcessor instance | ||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| > **Note:** Without `enableCustomElements = true`, custom components will not render even if they are properly registered, because the flag defaults to `false`. | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| ## 4. Invoking from the Agent | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that bit was referencing the v0.8 "enableCustomElement", but now that this shows up earlier in the document I think it doesn't make sense.