a2ui-project / a2ui-project/a2ui
Make renderer library APIs more consistent
- Lingua principale
- TypeScript
- Stelle
- 16.4k
- Fork
- 1.3k
- Merge medio
- 2g 13h
- PR unite (30g)
- 134
Descrizione
The three renderer libraries are somewhat inconsistent. Here is a comparison doc from Gemini. We can think about what changes make sense here.
# A2UI Renderer API Surface Comparison
This document provides a detailed comparison of the API surfaces for the three A2UI renderers: Web (Lit), Angular, and Flutter. It highlights the key differences and similarities in how each library is used, with a focus on usage examples rather than API definitions.
## Surfaces Management
This section describes how each renderer manages the creation and data flow for UI surfaces.
### Web (Lit)
In the Lit renderer, the application is responsible for creating and managing the lifecycle of `` components. The library does not automatically create them when a new `surfaceId` is seen.
**Creating a New Surface & Supplying Data:**
The application code must listen for new surfaces and manually create the corresponding DOM element. Data, in the form of the `surface` state object and the `processor` instance, is passed down as properties.
```typescript
// Application code
const processor = createSignalA2UIModelProcessor();
const surfaces = processor.getSurfaces();
// When a new surface is detected (e.g., from a message):
const surfaceElement = document.createElement('a2ui-surface');
surfaceElement.surfaceId = newSurfaceId;
surfaceElement.processor = processor;
surfaceElement.surface = surfaces.get(newSurfaceId);
document.body.appendChild(surfaceElement);
```
*(See: `web/lib/src/0.8/ui/surface.ts` for component definition)*
### Angular
The Angular renderer follows a similar pattern to the Lit renderer. The application is responsible for creating `` components, typically by iterating over a list of active surface IDs.
**Creating a New Surface & Supplying Data:**
Data is passed to the surface component via Angular's `@input()` bindings. A common pattern is to use `*ngFor` to render a list of surfaces.
```typescript
// app.component.ts
import { Component } from '@angular/core';
import { ModelProcessor } from '@a2ui/angular-lib'; // Assuming library import
@Component({
selector: 'app-root',
template: `
`,
})
export class AppComponent {
surfaceIds: string[] = []; // Managed by the application
constructor(public processor: ModelProcessor) {
// Logic to update surfaceIds as they are added/removed
}
}
```
*(See: `angular/projects/lib/src/lib/catalog/surface.ts` for component definition)*
### Flutter
The Flutter renderer uses a more automated, callback-driven approach. The `GenUiConversation` facade notifies the application when surfaces are added or removed, and the application code is responsible for building the corresponding `GenUiSurface` widget.
**Creating a New Surface & Supplying Data:**
The `onSurfaceAdded` callback provides the `surfaceId`. The application then builds a `GenUiSurface` widget, passing it the `host` (the `GenUiManager` instance) and the `surfaceId`. The widget communicates with the host to get its data, abstracting the data flow from the application developer.
```dart
// From: .guides/docs/connect_to_agent_provider.md
class _MyHomePageState extends State {
late final GenUiConversation _genUiConversation;
final _surfaceIds = [];
@override
void initState() {
super.initState();
_genUiConversation = GenUiConversation(
// ...
onSurfaceAdded: (update) {
setState(() => _surfaceIds.add(update.surfaceId));
},
onSurfaceDeleted: (update) {
setState(() => _surfaceIds.remove(update.surfaceId));
},
);
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _surfaceIds.length,
itemBuilder: (context, index) {
final id = _surfaceIds[index];
// The GenUiSurface widget handles its own data fetching via the host
return GenUiSurface(host: _genUiConversation.host, surfaceId: id);
},
);
}
}
```
*(See: `lib/src/core/genui_surface.dart` for widget definition)*
## Data Model
This section covers how the data model for each surface is updated and accessed.
### Web (Lit)
The `A2UIModelProcessor` is responsible for the data model. It processes incoming A2UI messages to update its internal state. It also provides a public API for direct, imperative access to the data.
**Updating and Accessing Data:**
- **A2UI Messages**: `processor.processMessages(messages)` automatically updates the model.
- **Direct Access**: `processor.setData()` and `processor.getData()` allow for direct manipulation.
```typescript
// Direct write
processor.setData(componentNode, '/user/name', 'John Doe', surfaceId);
// Direct read
const userName = processor.getData(componentNode, '/user/name', surfaceId);
```
*(See: `web/lib/src/0.8/data/model-processor.ts`)*
### Angular
The Angular library wraps the `A2UIModelProcessor` in an injectable `ModelProcessor` service, which provides the same API for direct data access.
**Updating and Accessing Data:**
- **A2UI Messages**: The `makeRequest` method handles fetching and processing messages.
- **Direct Access**: The service exposes `setData()` and `getData()`.
```typescript
// In an Angular component
import { ModelProcessor } from '@a2ui/angular-lib';
// ...
constructor(private processor: ModelProcessor) {}
updateName(newName: string) {
// Direct write
this.processor.setData(this.component, '/user/name', newName, this.surfaceId);
}
```
*(See: `angular/projects/lib/src/lib/data/processor.ts`)*
### Flutter
In Flutter, the `DataModel` is managed by the `GenUiManager`. Direct interaction is done through a `DataContext` object that is passed down to each widget's builder function. This provides a scoped and reactive way to interact with the data.
**Updating and Accessing Data:**
- **A2UI Messages**: The `GenUiManager` automatically handles `DataModelUpdate` messages.
- **Direct Access**: The `DataContext` provides `update()`, `getValue()`, and `subscribe()` methods.
```dart
// Inside a CatalogItem's widgetBuilder
final textField = CatalogItem(
name: 'TextField',
widgetBuilder: (itemContext) {
// ...
return TextField(
onChanged: (newValue) {
// Direct write via DataContext
if (path != null) {
itemContext.dataContext.update(DataPath(path), newValue);
}
},
);
},
);
```
*(See: `lib/src/model/data_model.dart`)*
## Message Handling
This section compares how the renderers process incoming messages from the server.
### Web (Lit) & Angular
Both web renderers assume that messages have already been received from a server. The application code is responsible for fetching the messages (e.g., via WebSocket or HTTP) and passing them to the processor. Messages are represented as plain JSON objects. Routing to a specific surface is handled internally by the `A2UIModelProcessor` based on the `surfaceId` in each message.
**Usage:**
```typescript
// Application code is responsible for this part
const messages = await fetchMessagesFromServer(); // Returns JSON[]
// Pass messages to the processor
processor.processMessages(messages);
```
*(See: `web/lib/src/0.8/data/model-processor.ts`)*
### Flutter
The Flutter library includes a higher-level abstraction for communication. The `ContentGenerator` interface is responsible for connecting to the server and receiving messages. The `GenUiConversation` class orchestrates this process. Messages are strongly-typed Dart classes (`SurfaceUpdate`, `DataModelUpdate`, etc.), not raw JSON. Routing is fully automated.
**Usage:**
The developer does not handle messages directly. Instead, you implement a `ContentGenerator` and the `GenUiConversation` handles the rest.
```dart
// The ContentGenerator is responsible for server communication
class MyContentGenerator implements ContentGenerator {
final _a2uiMessageController = StreamController();
@override
Stream get a2uiMessageStream => _a2uiMessageController.stream;
Future fetchAndProcess() {
// 1. Fetch data from server
// 2. Parse into A2uiMessage objects
// 3. Add to the stream
_a2uiMessageController.add(parsedMessage);
}
// ...
}
```
*(See: `lib/src/content_generator.dart` and `lib/src/conversation/gen_ui_conversation.dart`)*
## Custom Catalogs
This section details how to define and register custom UI components.
### Web (Lit)
The Lit renderer **does not** have a public API for registering custom components. To add a new component, the library's source code must be modified.
*(See: `web/lib/src/0.8/ui/root.ts` in the `renderComponentTree` method)*
### Angular
The Angular renderer is designed for extensibility and uses dependency injection to provide custom catalogs.
**Defining and Providing a Catalog:**
You create a `Catalog` object and provide it to your application using the `provideA2UI` function. A `CatalogEntry` maps a component name to an Angular component `Type` and defines its input bindings.
```typescript
// From: angular/projects/lib/src/lib/config.ts (Definition)
// Usage in app.config.ts
import { provideA2UI, DEFAULT_CATALOG } from '@a2ui/angular-lib';
import { MyCustomComponent } from './my-custom.component';
const myCustomCatalog = {
...DEFAULT_CATALOG,
'MyCustomComponent': {
type: () => MyCustomComponent,
bindings: ({ properties }) => [
inputBinding('title', () => properties.title),
],
}
};
export const appConfig: ApplicationConfig = {
providers: [
provideA2UI({
catalog: myCustomCatalog,
// ... theme and client
})
]
};
```
*(See: `angular/projects/lib/src/lib/rendering/catalog.ts` and `angular/projects/lib/src/lib/config.ts`)*
### Flutter
Flutter also has a first-class API for custom catalogs. A `Catalog` is a collection of `CatalogItem` objects and is passed to the `GenUiManager` during initialization.
**Defining and Providing a Catalog:**
A `CatalogItem` contains a `name`, a `dataSchema`, and a `widgetBuilder` function. The builder has access to a `CatalogItemContext`, which includes the component's `data`, the current `dataContext`, and a `buildChild` function for recursion.
```dart
// From: .guides/docs/create_a_custom_catalogitem.md
// 1. Define the CatalogItem
final riddleCard = CatalogItem(
name: 'RiddleCard',
dataSchema: _schema,
widgetBuilder: ({ required data, required dataContext, ... }) {
// ... access data and build a Flutter widget
return Container(...);
},
);
// 2. Provide it to the GenUiManager
final genUiManager = GenUiManager(
catalog: CoreCatalogItems.asCatalog().copyWith([riddleCard]),
);
```
*(See: `lib/src/model/catalog.dart` and `lib/src/model/catalog_item.dart`)*
## Events
This section explains how user interactions are captured and sent back to the server.
### Web (Lit)
The Lit components dispatch a global `a2uiaction` custom DOM event. The application is responsible for listening to this event and sending the payload to the server. The event detail is surface-agnostic but contains the `sourceComponentId`.
**Usage:**
```typescript
// Application code
window.addEventListener('a2uiaction', (e) => {
const { action, dataContextPath, sourceComponentId } = e.detail;
// Logic to resolve context and send to server
const payload = {
userAction: {
name: action.name,
sourceComponentId: sourceComponentId,
// ... resolve context from dataContextPath
}
};
sendToServer(payload);
});
```
*(See: `web/lib/src/0.8/events/events.ts`)*
### Angular
The `DynamicComponent` base class provides a `sendAction` helper method. This method resolves the action's context and calls the `ModelProcessor.makeRequest` method, abstracting away the event handling and server communication from the component developer.
**Usage:**
```typescript
// Inside a custom button component
import { DynamicComponent } from '@a2ui/angular-lib';
// ...
export class MyButton extends DynamicComponent {
// ...
handleClick() {
if (this.action) {
// sendAction handles context resolution and server communication
super.sendAction(this.action);
}
}
}
```
*(See: `angular/projects/lib/src/lib/rendering/dynamic-component.ts`)*
### Flutter
The `widgetBuilder` function in a `CatalogItem` is provided with a `dispatchEvent` callback. When a user interaction occurs, this function is called with a `UserActionEvent`. The `GenUiManager` automatically captures this event, enriches it with the surface ID, and forwards it to the `ContentGenerator` to be sent to the server.
**Usage:**
```dart
// From: lib/src/catalog/core_widgets/button.dart
final button = CatalogItem(
name: 'Button',
widgetBuilder: (itemContext) {
// ...
return ElevatedButton(
onPressed: () {
// dispatchEvent is provided by the context
itemContext.dispatchEvent(
UserActionEvent(
name: actionName,
sourceComponentId: itemContext.id,
context: resolvedContext,
),
);
},
child: child,
);
},
);
```
*(See: `lib/src/model/ui_models.dart`)*
## Conversation Management
This section looks at utilities for managing the back-and-forth dialogue with the AI.
### Web (Lit) & Angular
Neither of the web renderers includes built-in utilities for conversation management. The application is entirely responsible for maintaining the chat history and sending it with each request to the server.
### Flutter
The Flutter library provides the `GenUiConversation` class, a high-level facade that completely manages the conversation. It automatically maintains the history of `ChatMessage` objects (including user text, AI text, and UI responses) and sends it with each request.
**Usage:**
```dart
// From: lib/src/conversation/gen_ui_conversation.dart (Definition)
// Application code
_genUiConversation = GenUiConversation(
genUiManager: genUiManager,
contentGenerator: contentGenerator,
// ... callbacks
);
// Sending a message automatically includes history
_genUiConversation.sendRequest(UserMessage.text(text));
```
*(See: `lib/src/conversation/gen_ui_conversation.dart`)*
## Recommendations for API Consistency
This section details areas where the API surfaces differ significantly without a clear platform-specific reason. Adopting these recommendations would create a more consistent developer experience across all three renderers.
### 1. Introduce a High-Level Conversation Manager for Web
**Inconsistency**: The Flutter library provides a high-level `GenUiConversation` facade that manages state, conversation history, and server communication. The web libraries lack this, forcing the application developer to manually handle message fetching, processing, and history management.
**Recommendation**: Introduce a `GenUiConversation` class to both the Lit and Angular libraries. This class would encapsulate the `A2UIModelProcessor` and a new `ContentGenerator` interface (similar to Flutter's), providing a single, simplified entry point for developers.
**Example of Proposed Web API:**
```typescript
// Proposed API
const conversation = new GenUiConversation({
contentGenerator: new MyContentGenerator(), // App-provided server connection
});
// Listen for surface changes, similar to Flutter's callbacks
conversation.onSurfaceAdded = (surfaceId, surface) => {
// App logic to render the new surface
};
// Sending a message becomes a single method call
function send(text: string) {
conversation.sendRequest({ text });
}
```
This would align the web libraries with the more streamlined, developer-friendly approach of the Flutter library.
### 2. Add a Public API for Custom Catalogs to the Lit Renderer
**Inconsistency**: The Angular and Flutter renderers provide powerful, idiomatic ways to register custom components. The Lit renderer has no public API for this, requiring developers to modify the library's source code to extend it.
**Recommendation**: Add a public API to the Lit renderer for registering custom components. This would involve creating a `Catalog` that maps A2UI component names to definitions that include the web component's tag name and a way to map properties.
#### API Sketch and Comparison
The proposed API would mirror the declarative nature of the Angular and Flutter catalogs.
* **Flutter API (`lib/src/model/catalog_item.dart`):**
```dart
final riddleCard = CatalogItem(
name: 'RiddleCard',
dataSchema: _schema,
widgetBuilder: ({ data, ... }) { /* returns a Widget */ },
);
```
* **Angular API (`angular/projects/lib/src/lib/rendering/catalog.ts`):**
```typescript
const myCustomCatalog = {
'MyCustomComponent': {
type: () => MyCustomComponent,
bindings: ({ properties }) => [ /* ... */ ],
}
};
```
* **Proposed Lit API:**
A `CatalogEntry` would define the tag name and a `propertyMapper` function. A new `A2UIModelProcessor` constructor would accept a catalog.
```typescript
// Proposed definition for a catalog entry
interface CatalogEntry {
tagName: string;
propertyMapper: (properties: Record) => Record;
}
// Proposed usage
const customCatalog = {
'MyCustomComponent': {
tagName: 'my-custom-component',
propertyMapper: (props) => ({
// map A2UI properties to the web component's properties
title: props.header,
items: props.listItems
})
}
};
const processor = createSignalA2UIModelProcessor({ catalog: customCatalog });
```
#### Refactoring the Standard Catalog
With this new API, the hardcoded `switch` statement in `web/lib/src/0.8/ui/root.ts` would be removed. Instead, a default catalog would be defined in a new file (e.g., `web/lib/src/0.8/ui/catalog.ts`).
**Example of a new `catalog.ts`:**
```typescript
// web/lib/src/0.8/ui/catalog.ts
// The default catalog defines all the standard components
export const DEFAULT_CATALOG: Record = {
'Card': {
tagName: 'a2ui-card',
propertyMapper: (props) => ({
// The childComponents logic would be handled by the root renderer
})
},
'Text': {
tagName: 'a2ui-text',
propertyMapper: (props) => ({
text: props.text
})
},
// ... all other standard components
};
// The processor would use this by default
const processor = createSignalA2UIModelProcessor({
catalog: { ...DEFAULT_CATALOG, ...customCatalog }
});
```
The `renderComponentTree` method in `a2ui-root` would then dynamically look up the component in the processor's catalog and create the element, making the entire system extensible.
### 3. Unify Event Handling Logic
**Inconsistency**: When a user action occurs, the Angular and Flutter libraries handle the resolution of data-bound context internally before notifying the application. The Lit renderer, however, dispatches a DOM event with unresolved data paths, forcing the application to perform the context resolution itself.
**Recommendation**: The Lit renderer should resolve the action context *before* dispatching the `a2uiaction` event. The library's internal components should use their reference to the `processor` to look up the data values, creating a fully-formed payload that is ready to be sent to the server.
**Example of Change in Lit Event Handling:**
**Before (Current):**
```typescript
// Application code
window.addEventListener('a2uiaction', (e) => {
const { action, dataContextPath } = e.detail;
// App developer must manually resolve the context
const resolvedContext = {};
for (const item of action.context) {
if (item.value.path) {
const fullPath = processor.resolvePath(item.value.path, dataContextPath);
resolvedContext[item.key] = processor.getDataByPath(fullPath);
}
// ... handle literals
}
// ... send to server
});
```
**After (Proposed):**
```typescript
// Application code
window.addEventListener('a2uiaction', (e) => {
// The event detail now contains the fully resolved context
const { userAction } = e.detail;
// The payload is ready to be sent
sendToServer({ userAction });
});
```
This would reduce boilerplate code in the application and make the event handling logic consistent across all three platforms.
## Terminology and API Consistency Review
This section reviews terminology used across the different renderers and suggests changes to improve consistency.
### State Management: `ModelProcessor` vs. `GenUiManager`
**Inconsistency**:
- **Web (Lit/Angular)**: The core state management class is `A2UIModelProcessor` (or `ModelProcessor` in the Angular wrapper). Its primary role is to process A2UI messages and manage the data model.
- **Flutter**: The core state management class is `GenUiManager`. It performs the same duties as the `ModelProcessor` but also has a broader role as a `GenUiHost`, managing surface lifecycles and handling UI events.
While the Flutter `GenUiManager` has more responsibilities due to the higher-level abstractions of that library (like `GenUiConversation`), the core functionality of processing messages and managing state is identical. The different naming can be confusing.
**Recommendation**:
To improve clarity, align the naming of the core message-processing and state-management entity.
1. **Rename `GenUiManager` in Flutter to `A2UIModelProcessor`**. This would make the core class consistent across all platforms.
2. The existing `GenUiManager` could then become a higher-level class that *contains* an `A2UIModelProcessor` instance, clarifying the separation of concerns.
This change would make it easier for developers to switch between platforms, as the central state management object would have the same name and a very similar API everywhere.
### Component Properties: `Card`'s `child` vs. `children`
**Inconsistency**:
- **A2UI Specification**: The formal spec for the `Card` component requires a single `child` property.
- **Flutter Renderer**: The Flutter `card.dart` widget correctly adheres to the spec, only accepting a single `child`.
- **Web (Lit/Angular) Renderers**: Both web renderers contain logic to handle either a `child` property or a `children` property. This is a deviation from the specification and adds unnecessary complexity.
**Recommendation**:
The web renderers should be updated to strictly adhere to the A2UI specification.
1. **Perform a find/replace** in `web/lib/src/0.8/data/guards.ts` and `angular/projects/lib/src/lib/catalog/card.ts` to remove the logic that handles the `children` property for the `Card` component.
2. The `Card` component should only accept a single `child`, as defined in the specification.
This change would enforce consistency with the protocol, simplify the codebase of the web renderers, and align them with the Flutter implementation. If a card with multiple children is desired, a new component type should be proposed for the A2UI specification.
*(See: `web/lib/src/0.8/events/events.ts`)*
### Angular
The `DynamicComponent` base class provides a `sendAction` helper method. This method resolves the action's context and calls the `ModelProcessor.makeRequest` method, abstracting away the event handling and server communication from the component developer.
**Usage:**
```typescript
// Inside a custom button component
import { DynamicComponent } from '@a2ui/angular-lib';
// ...
export class MyButton extends DynamicComponent {
// ...
handleClick() {
if (this.action) {
// sendAction handles context resolution and server communication
super.sendAction(this.action);
}
}
}
```
*(See: `angular/projects/lib/src/lib/rendering/dynamic-component.ts`)*
### Flutter
The `widgetBuilder` function in a `CatalogItem` is provided with a `dispatchEvent` callback. When a user interaction occurs, this function is called with a `UserActionEvent`. The `GenUiManager` automatically captures this event, enriches it with the surface ID, and forwards it to the `ContentGenerator` to be sent to the server.
**Usage:**
```dart
// From: lib/src/catalog/core_widgets/button.dart
final button = CatalogItem(
name: 'Button',
widgetBuilder: (itemContext) {
// ...
return ElevatedButton(
onPressed: () {
// dispatchEvent is provided by the context
itemContext.dispatchEvent(
UserActionEvent(
name: actionName,
sourceComponentId: itemContext.id,
context: resolvedContext,
),
);
},
child: child,
);
},
);
```
*(See: `lib/src/model/ui_models.dart`)*
## Conversation Management
This section looks at utilities for managing the back-and-forth dialogue with the AI.
### Web (Lit) & Angular
Neither of the web renderers includes built-in utilities for conversation management. The application is entirely responsible for maintaining the chat history and sending it with each request to the server.
### Flutter
The Flutter library provides the `GenUiConversation` class, a high-level facade that completely manages the conversation. It automatically maintains the history of `ChatMessage` objects (including user text, AI text, and UI responses) and sends it with each request.
**Usage:**
```dart
// From: lib/src/conversation/gen_ui_conversation.dart (Definition)
// Application code
_genUiConversation = GenUiConversation(
genUiManager: genUiManager,
contentGenerator: contentGenerator,
// ... callbacks
);
// Sending a message automatically includes history
_genUiConversation.sendRequest(UserMessage.text(text));
```
*(See: `lib/src/conversation/gen_ui_conversation.dart`)*
## Recommendations for API Consistency
This section details areas where the API surfaces differ significantly without a clear platform-specific reason. Adopting these recommendations would create a more consistent developer experience across all three renderers.
### 1. Introduce a High-Level Conversation Manager for Web
**Inconsistency**: The Flutter library provides a high-level `GenUiConversation` facade that manages state, conversation history, and server communication. The web libraries lack this, forcing the application developer to manually handle message fetching, processing, and history management.
**Recommendation**: Introduce a `GenUiConversation` class to both the Lit and Angular libraries. This class would encapsulate the `A2UIModelProcessor` and a new `ContentGenerator` interface (similar to Flutter's), providing a single, simplified entry point for developers.
**Example of Proposed Web API:**
```typescript
// Proposed API
const conversation = new GenUiConversation({
contentGenerator: new MyContentGenerator(), // App-provided server connection
});
// Listen for surface changes, similar to Flutter's callbacks
conversation.onSurfaceAdded = (surfaceId, surface) => {
// App logic to render the new surface
};
// Sending a message becomes a single method call
function send(text: string) {
conversation.sendRequest({ text });
}
```
This would align the web libraries with the more streamlined, developer-friendly approach of the Flutter library.
### 2. Add a Public API for Custom Catalogs to the Lit Renderer
**Inconsistency**: The Angular and Flutter renderers provide powerful, idiomatic ways to register custom components. The Lit renderer has no public API for this, requiring developers to modify the library's source code to extend it.
**Recommendation**: Add a public API to the Lit renderer for registering custom components. This could be implemented as a method on the `A2UIModelProcessor` or a new registry that the `` component can access.
**Example of Proposed Lit API:**
```typescript
import { MyCustomComponent } from './my-custom-component.js';
const processor = createSignalA2UIModelProcessor();
// New method to register a component
processor.registerComponent('MyCustomComponent', 'my-custom-component-tag');
// The would then know to render
// when it encounters a component of type "MyCustomComponent".
```
This change is critical for making the Lit renderer a viable, extensible option for developers.
### 3. Unify Event Handling Logic
**Inconsistency**: When a user action occurs, the Angular and Flutter libraries handle the resolution of data-bound context internally before notifying the application. The Lit renderer, however, dispatches a DOM event with unresolved data paths, forcing the application to perform the context resolution itself.
**Recommendation**: The Lit renderer should resolve the action context *before* dispatching the `a2uiaction` event. The library's internal components should use their reference to the `processor` to look up the data values, creating a fully-formed payload that is ready to be sent to the server.
**Example of Change in Lit Event Handling:**
**Before (Current):**
```typescript
// Application code
window.addEventListener('a2uiaction', (e) => {
const { action, dataContextPath } = e.detail;
// App developer must manually resolve the context
const resolvedContext = {};
for (const item of action.context) {
if (item.value.path) {
const fullPath = processor.resolvePath(item.value.path, dataContextPath);
resolvedContext[item.key] = processor.getDataByPath(fullPath);
}
// ... handle literals
}
// ... send to server
});
```
**After (Proposed):**
```typescript
// Application code
window.addEventListener('a2uiaction', (e) => {
// The event detail now contains the fully resolved context
const { userAction } = e.detail;
// The payload is ready to be sent
sendToServer({ userAction });
});
```
This would reduce boilerplate code in the application and make the event handling logic consistent across all three platforms.
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.