Skip to content
1 change: 1 addition & 0 deletions renderers/angular/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Unreleased

- (v0_9) Implement `createAngularComponentImplementation` helper and deprecate `extraComponents` and `functions` in `BasicCatalogOptions` to align with the core API. [#2060](https://github.com/a2ui-project/a2ui/pull/2060)
Comment thread
josemontespg marked this conversation as resolved.
Outdated
- Standardize package entry points to `index.ts` while maintaining `public-api.ts` wrappers for backward compatibility.
- (v0_8) Export `A2uiMessageSchema` in public API.

Expand Down
15 changes: 7 additions & 8 deletions renderers/angular/a2ui_explorer/src/app/demo-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import {Injectable} from '@angular/core';
import {BasicCatalogBase, BASIC_FUNCTIONS} from '@a2ui/angular/v0_9';
import {AngularCatalog, BASIC_COMPONENTS, BASIC_FUNCTIONS} from '@a2ui/angular/v0_9';
import {customSliderComponentDeclaration} from './custom-slider.component';

/**
Expand All @@ -24,13 +24,12 @@ import {customSliderComponentDeclaration} from './custom-slider.component';
@Injectable({
providedIn: 'root',
})
export class DemoCatalog extends BasicCatalogBase {
export class DemoCatalog extends AngularCatalog {
constructor() {
super({
id: 'https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json',
components: {},
extraComponents: [customSliderComponentDeclaration],
functions: BASIC_FUNCTIONS,
});
super(
'https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json',
[...BASIC_COMPONENTS, customSliderComponentDeclaration],
BASIC_FUNCTIONS
);
}
}
42 changes: 23 additions & 19 deletions renderers/angular/src/v0_9/catalog/basic/basic-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import {Inject, Injectable, InjectionToken, Optional} from '@angular/core';
import {AngularCatalog, AngularComponentImplementation} from '../types';
import {AngularCatalog, AngularComponentImplementation, createAngularComponentImplementation} from '../types';
import {TextComponent} from './text.component';
import {RowComponent} from './row.component';
import {ColumnComponent} from './column.component';
Expand Down Expand Up @@ -66,24 +66,24 @@ import {FunctionImplementation} from '@a2ui/web_core/v0_9';
// Ignore Prettier to preserve quoted keys, needed to survive property renaming.
// prettier-ignore
const DEFAULT_COMPONENT_IMPLEMENTATIONS: Record<string, AngularComponentImplementation> = {
'text': {...TextApi, component: TextComponent},
'row': {...RowApi, component: RowComponent},
'column': {...ColumnApi, component: ColumnComponent},
'button': {...ButtonApi, component: ButtonComponent},
'textField': {...TextFieldApi, component: TextFieldComponent},
'image': {...ImageApi, component: ImageComponent},
'icon': {...IconApi, component: IconComponent},
'video': {...VideoApi, component: VideoComponent},
'audioPlayer': {...AudioPlayerApi, component: AudioPlayerComponent},
'list': {...ListApi, component: ListComponent},
'card': {...CardApi, component: CardComponent},
'tabs': {...TabsApi, component: TabsComponent},
'modal': {...ModalApi, component: ModalComponent},
'divider': {...DividerApi, component: DividerComponent},
'checkBox': {...CheckBoxApi, component: CheckBoxComponent},
'choicePicker': {...ChoicePickerApi, component: ChoicePickerComponent},
'slider': {...SliderApi, component: SliderComponent},
'dateTimeInput': {...DateTimeInputApi, component: DateTimeInputComponent},
'text': createAngularComponentImplementation(TextApi, TextComponent),
'row': createAngularComponentImplementation(RowApi, RowComponent),
'column': createAngularComponentImplementation(ColumnApi, ColumnComponent),
'button': createAngularComponentImplementation(ButtonApi, ButtonComponent),
'textField': createAngularComponentImplementation(TextFieldApi, TextFieldComponent),
'image': createAngularComponentImplementation(ImageApi, ImageComponent),
'icon': createAngularComponentImplementation(IconApi, IconComponent),
'video': createAngularComponentImplementation(VideoApi, VideoComponent),
'audioPlayer': createAngularComponentImplementation(AudioPlayerApi, AudioPlayerComponent),
'list': createAngularComponentImplementation(ListApi, ListComponent),
'card': createAngularComponentImplementation(CardApi, CardComponent),
'tabs': createAngularComponentImplementation(TabsApi, TabsComponent),
'modal': createAngularComponentImplementation(ModalApi, ModalComponent),
'divider': createAngularComponentImplementation(DividerApi, DividerComponent),
'checkBox': createAngularComponentImplementation(CheckBoxApi, CheckBoxComponent),
'choicePicker': createAngularComponentImplementation(ChoicePickerApi, ChoicePickerComponent),
'slider': createAngularComponentImplementation(SliderApi, SliderComponent),
'dateTimeInput': createAngularComponentImplementation(DateTimeInputApi, DateTimeInputComponent),
} as const;

/**
Expand All @@ -110,11 +110,15 @@ export interface BasicCatalogOptions {
/**
* Optional additional components to include in the catalog beyond
* the standard basic catalog components.
*
* @deprecated Use AngularCatalog constructor directly to combine BASIC_COMPONENTS with custom ones.
*/
extraComponents?: AngularComponentImplementation[];

/**
* An optional set of function implementations to use instead of the defaults.
*
* @deprecated Use AngularCatalog constructor directly to combine BASIC_FUNCTIONS with custom ones.
*/
functions?: FunctionImplementation[];
Comment thread
josemontespg marked this conversation as resolved.
}
Expand Down
43 changes: 43 additions & 0 deletions renderers/angular/src/v0_9/catalog/types.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {Component} from '@angular/core';
import {ComponentApi} from '@a2ui/web_core/v0_9';
import {createAngularComponentImplementation} from './types';
import {CatalogComponent} from '../core/catalog_component';
import {z} from 'zod';

@Component({
selector: 'test-comp',
template: '',
standalone: true,
})
class TestComponent extends CatalogComponent<ComponentApi> {}

describe('createAngularComponentImplementation', () => {
it('should map ComponentApi and Angular Component Type correctly', () => {
const api: ComponentApi = {
name: 'TestComp',
schema: z.object({}),
};

const impl = createAngularComponentImplementation(api, TestComponent);

expect(impl.name).toBe('TestComp');
expect(impl.schema).toEqual(api.schema);
expect(impl.component).toBe(TestComponent);
});
});
21 changes: 21 additions & 0 deletions renderers/angular/src/v0_9/catalog/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,24 @@ export interface AngularComponentImplementation extends ComponentApi {
* correct Angular components.
*/
export class AngularCatalog extends Catalog<AngularComponentImplementation> {}

/**
* Helper function to create an {@link AngularComponentImplementation}.
*
* It extracts the name and schema from a generic {@link ComponentApi} and
* associates it with the given Angular component type.
*
* @param api The generic component API definition.
* @param component The Angular component class implementing the API.
* @returns The structured Angular component implementation.
*/
export function createAngularComponentImplementation(
Comment thread
josemontespg marked this conversation as resolved.
Outdated
Comment thread
josemontespg marked this conversation as resolved.
Outdated
Comment thread
josemontespg marked this conversation as resolved.
Outdated
api: ComponentApi,
component: Type<CatalogComponentInstance>,
): AngularComponentImplementation {
return {
name: api.name,
schema: api.schema,
component,
};
Comment thread
josemontespg marked this conversation as resolved.
}
Loading