diff --git a/renderers/angular/CHANGELOG.md b/renderers/angular/CHANGELOG.md index 7e2201117c..cbb060eb8a 100644 --- a/renderers/angular/CHANGELOG.md +++ b/renderers/angular/CHANGELOG.md @@ -1,5 +1,6 @@ ## Unreleased +- (v0_9) Implement `createComponentImplementation` helper and deprecate `extraComponents` and `functions` in `BasicCatalogOptions` to align with the core API. [#2060](https://github.com/a2ui-project/a2ui/pull/2060) - Add standalone helper `provideA2Ui` configuration function. [#2061](https://github.com/a2ui-project/a2ui/pull/2061) - Standardize package entry points to `index.ts` while maintaining `public-api.ts` wrappers for backward compatibility. - (v0_8) Export `A2uiMessageSchema` in public API. diff --git a/renderers/angular/a2ui_explorer/src/app/demo-catalog.ts b/renderers/angular/a2ui_explorer/src/app/demo-catalog.ts index 14b179b0db..39c9f008ba 100644 --- a/renderers/angular/a2ui_explorer/src/app/demo-catalog.ts +++ b/renderers/angular/a2ui_explorer/src/app/demo-catalog.ts @@ -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'; /** @@ -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 + ); } } diff --git a/renderers/angular/src/v0_9/catalog/basic/basic-catalog.ts b/renderers/angular/src/v0_9/catalog/basic/basic-catalog.ts index 215d60b3e8..f55961f2e2 100644 --- a/renderers/angular/src/v0_9/catalog/basic/basic-catalog.ts +++ b/renderers/angular/src/v0_9/catalog/basic/basic-catalog.ts @@ -15,7 +15,7 @@ */ import {Inject, Injectable, InjectionToken, Optional} from '@angular/core'; -import {AngularCatalog, AngularComponentImplementation} from '../types'; +import {AngularCatalog, AngularComponentImplementation, createComponentImplementation} from '../types'; import {TextComponent} from './text.component'; import {RowComponent} from './row.component'; import {ColumnComponent} from './column.component'; @@ -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 = { - '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': createComponentImplementation(TextApi, TextComponent), + 'row': createComponentImplementation(RowApi, RowComponent), + 'column': createComponentImplementation(ColumnApi, ColumnComponent), + 'button': createComponentImplementation(ButtonApi, ButtonComponent), + 'textField': createComponentImplementation(TextFieldApi, TextFieldComponent), + 'image': createComponentImplementation(ImageApi, ImageComponent), + 'icon': createComponentImplementation(IconApi, IconComponent), + 'video': createComponentImplementation(VideoApi, VideoComponent), + 'audioPlayer': createComponentImplementation(AudioPlayerApi, AudioPlayerComponent), + 'list': createComponentImplementation(ListApi, ListComponent), + 'card': createComponentImplementation(CardApi, CardComponent), + 'tabs': createComponentImplementation(TabsApi, TabsComponent), + 'modal': createComponentImplementation(ModalApi, ModalComponent), + 'divider': createComponentImplementation(DividerApi, DividerComponent), + 'checkBox': createComponentImplementation(CheckBoxApi, CheckBoxComponent), + 'choicePicker': createComponentImplementation(ChoicePickerApi, ChoicePickerComponent), + 'slider': createComponentImplementation(SliderApi, SliderComponent), + 'dateTimeInput': createComponentImplementation(DateTimeInputApi, DateTimeInputComponent), } as const; /** @@ -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[]; } diff --git a/renderers/angular/src/v0_9/catalog/types.spec.ts b/renderers/angular/src/v0_9/catalog/types.spec.ts new file mode 100644 index 0000000000..98de267008 --- /dev/null +++ b/renderers/angular/src/v0_9/catalog/types.spec.ts @@ -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 {createComponentImplementation} from './types'; +import {CatalogComponent} from '../core/catalog_component'; +import {z} from 'zod'; + +@Component({ + selector: 'test-comp', + template: '', + standalone: true, +}) +class TestComponent extends CatalogComponent {} + +describe('createComponentImplementation', () => { + it('should map ComponentApi and Angular Component Type correctly', () => { + const api: ComponentApi = { + name: 'TestComp', + schema: z.object({}), + }; + + const impl = createComponentImplementation(api, TestComponent); + + expect(impl.name).toBe('TestComp'); + expect(impl.schema).toEqual(api.schema); + expect(impl.component).toBe(TestComponent); + }); +}); diff --git a/renderers/angular/src/v0_9/catalog/types.ts b/renderers/angular/src/v0_9/catalog/types.ts index 99f43dc3de..88076289ac 100644 --- a/renderers/angular/src/v0_9/catalog/types.ts +++ b/renderers/angular/src/v0_9/catalog/types.ts @@ -49,3 +49,24 @@ export interface AngularComponentImplementation extends ComponentApi { * correct Angular components. */ export class AngularCatalog extends Catalog {} + +/** + * 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 createComponentImplementation( + api: ComponentApi, + component: Type, +): AngularComponentImplementation { + return { + name: api.name, + schema: api.schema, + component, + }; +}