Skip to content

feat(angular): support universal web components in v0.9 renderer - #2211

Closed
josemontespg wants to merge 2 commits into
basic-catalog-universal-componentsfrom
angular-renderer-universal-components
Closed

feat(angular): support universal web components in v0.9 renderer#2211
josemontespg wants to merge 2 commits into
basic-catalog-universal-componentsfrom
angular-renderer-universal-components

Conversation

@josemontespg

@josemontespg josemontespg commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR enables the Angular v0.9 renderer to seamlessly consume universal Web Components from @a2ui/web_core and provide a bridge for Angular-native components:

  • Universal Web Components Support: Default Basic Catalog implementations now leverage the shared, tested Web Components in @a2ui/web_core.
  • Angular-to-Web-Component Bridge: Added toWebComponent adapter with dynamic injector lookup and lifecycle detachment handling to register Angular components into Catalog<WebComponentImplementation>.
  • Reactive Surface Lifecycle: Refactored SurfaceComponent to use Angular signal reactive effect for surface mounting, eliminating redundant lifecycle triggers.

Verification

  • yarn --cwd renderers/angular test:unit passed (259/259 tests).
  • yarn --cwd renderers/angular test:integration passed (204/204 tests).
  • yarn format:all && yarn lint:all passed cleanly with 0 errors across the monorepo.

Resolves #1270

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the Angular renderer for A2UI v0.9 to transition from Angular-specific component implementations to universal Web Components, updating SurfaceComponent to directly mount custom elements and updating AngularCatalog to bridge Angular components via toWebComponent. Feedback on these changes highlights a potential stale injector issue in toWebComponent due to global custom element registration, redundant lifecycle hooks in SurfaceComponent that duplicate the reactive effect logic, and a silent rendering failure risk in ComponentHostComponent for migrated components that lack an Angular component class.

Comment thread renderers/angular/src/v0_9/catalog/to_web_component.ts
Comment thread renderers/angular/src/v0_9/core/surface.component.ts Outdated
Comment thread renderers/angular/src/v0_9/core/component-host.component.ts Outdated
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from eeb6375 to a5d1df7 Compare August 8, 2026 00:52
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch from bd96f18 to 502f268 Compare August 8, 2026 00:52
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from a5d1df7 to a2ba300 Compare August 8, 2026 02:44
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch from 502f268 to 53e4f09 Compare August 8, 2026 02:45
Comment thread renderers/angular/a2ui_explorer/src/app/tests/v0_9/36_modal.spec.ts
Comment thread renderers/angular/src/v0_9/catalog/basic/basic-catalog.ts
Comment thread renderers/angular/src/v0_9/core/component-host.component.ts
Comment thread renderers/angular/src/v0_9/core/component-host.component.ts Outdated
Comment thread renderers/angular/src/v0_9/core/surface.component.ts Outdated
Comment thread renderers/lit/CHANGELOG.md Outdated
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 2 times, most recently from 941f7f3 to 4e418de Compare August 8, 2026 03:16
Comment thread renderers/angular/src/v0_9/core/component-host.component.ts
Comment thread renderers/angular/src/v0_9/core/component-host.component.ts Outdated
Comment thread renderers/angular/src/v0_9/index.ts
Comment thread renderers/lit/CHANGELOG.md Outdated
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch from 4e418de to 63c1e79 Compare August 8, 2026 03:31
@josemontespg
josemontespg marked this pull request as draft August 8, 2026 03:41
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from a2ba300 to cf228ac Compare August 8, 2026 03:42
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 2 times, most recently from 6979ea1 to 18af221 Compare August 8, 2026 04:04
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from cf228ac to acbd410 Compare August 8, 2026 04:12
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 2 times, most recently from 7591651 to cb24871 Compare August 8, 2026 05:48
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from acbd410 to 6ec7083 Compare August 8, 2026 05:48
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch from cb24871 to 88aaa5f Compare August 8, 2026 05:50
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from 6ec7083 to f771a10 Compare August 8, 2026 05:52
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 2 times, most recently from 1365263 to 5606bfd Compare August 12, 2026 17:23
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from f771a10 to 5a40d20 Compare August 12, 2026 17:23
@josemontespg
josemontespg marked this pull request as ready for review August 12, 2026 17:47
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 2 times, most recently from f0dc737 to 9899d0c Compare August 12, 2026 18:22
@sugoi-yuzuru
sugoi-yuzuru force-pushed the basic-catalog-universal-components branch from 5a40d20 to e97d174 Compare August 12, 2026 19:44
@sugoi-yuzuru
sugoi-yuzuru force-pushed the angular-renderer-universal-components branch from 9899d0c to ab6bcee Compare August 12, 2026 19:44
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from e97d174 to 5a40d20 Compare August 12, 2026 20:38
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch from ab6bcee to 9899d0c Compare August 12, 2026 20:38
@josemontespg
josemontespg marked this pull request as draft August 12, 2026 20:47
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch 2 times, most recently from cc02a75 to 9281cca Compare August 12, 2026 23:41
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 3 times, most recently from b441cb1 to 3dcf3dd Compare August 13, 2026 18:44
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from 9281cca to 418ea80 Compare August 13, 2026 19:02
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch from 3dcf3dd to 5c6f383 Compare August 13, 2026 19:02
@josemontespg
josemontespg force-pushed the basic-catalog-universal-components branch from 418ea80 to 50b886f Compare August 13, 2026 19:04
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 7 times, most recently from 61ef404 to 4fd5ee1 Compare August 14, 2026 00:46
* A component implementation supported by the Angular catalog, which can be
* either a native W3C Custom Element or an Angular `@Component` declaration.
*/
export type BasicCatalogComponent = WebComponentImplementation | AngularComponentImplementation;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be just CatalogComponent, since this can be used by other catalogs, not just the basic.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Renamed BasicCatalogComponent to CatalogComponent across all catalog definitions, services, and surfaces.

constructor() {
// Provide MarkdownRenderer context to the host DOM element so that any
// child Web Components (such as A2uiText) can access markdown rendering capabilities.
const md = inject(MarkdownRenderer, {optional: true});

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like an internal implementation detail of the Text component. Can this logic be encapsulated in the Text component, instead of having to provide it here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Moved the Markdown ContextProvider out of ComponentHostComponent and provided it at the surface root in SurfaceComponent, keeping ComponentHostComponent completely generic.

* 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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't remove the deprecation warnings

* @deprecated Use AngularCatalog constructor directly to combine BASIC_COMPONENTS with custom ones.
*/
extraComponents?: AngularComponentImplementation[];
extraComponents?: BasicCatalogComponent[];

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they should remain the same because the extra components might not be from the basic catalog.

export const BASIC_COMPONENTS: AngularComponentImplementation[] = Object.values(
DEFAULT_COMPONENT_IMPLEMENTATIONS,
);
export class NativeBasicCatalog extends AngularCatalog {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need to export these classes or are they just an implementation detail? if so remove the export keyword

configOrFactory: RendererConfiguration | (() => RendererConfiguration) = {},
): EnvironmentProviders {
const isFactory = typeof configOrFactory === 'function';
const initialConfig = isFactory ? {} : configOrFactory;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it is factory, should we call configOrFactory() ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undo the removal of these component catalog exports since we are not deleting the components anymore

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the changelog entry with the current implementation from the code changes. Also update the PR description

@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch 2 times, most recently from b9f71ec to 064cfa5 Compare August 14, 2026 17:57
@josemontespg
josemontespg force-pushed the angular-renderer-universal-components branch from 064cfa5 to 3bf9f98 Compare August 14, 2026 19:00
@josemontespg

Copy link
Copy Markdown
Collaborator Author

Superseded by #2273 after reordering universal markdown support before the Angular universal component adapter in the stack.

@github-project-automation github-project-automation Bot moved this from Todo to Done in A2UI Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support "portable A2UI web Components" which can be installed in a Catalog for *any* framework adapter

1 participant