{"_id":"@anycms/a2ui-angular","_rev":"2-6aa3fd4c6d058b3ab7c087e421fd7f6c","name":"@anycms/a2ui-angular","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.1":{"name":"@anycms/a2ui-angular","version":"0.1.1","keywords":["a2ui","anycms","generative-ui","angular","renderer","ai-ui"],"author":{"name":"Liangdi","email":"wu@liangdi.me"},"license":"MIT","_id":"@anycms/a2ui-angular@0.1.1","maintainers":[{"name":"wuliangdi","email":"wu@liangdi.me"}],"homepage":"https://github.com/anycms/a2ui","bugs":{"url":"https://github.com/anycms/a2ui/issues"},"dist":{"shasum":"f709e6ab11596940db7521dcdfe380e0df5eefca","tarball":"https://registry.npmjs.org/@anycms/a2ui-angular/-/a2ui-angular-0.1.1.tgz","fileCount":20,"integrity":"sha512-GohDZpNw7UnrtwnrjQdMxdDGuTQp8bzuAAsLxtlZzjaFyVekBWSEzJ8fEJijQvpZMIGrTv88R5qD+umm3q6Lfg==","signatures":[{"sig":"MEYCIQDgs0kAa9q7fFwoHmmYUOBW8I445kM94S0gJolkU0+mogIhAOzGdUNf4hYEFYyo5BAu98Se+gICMBOjDp6iKOqc+Zr0","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":227410},"type":"module","_from":"file:anycms-a2ui-angular-0.1.1.tgz","types":"dist/types/anycms-a2ui-angular.d.ts","module":"dist/fesm2022/anycms-a2ui-angular.mjs","exports":{".":{"types":"./dist/types/anycms-a2ui-angular.d.ts","default":"./dist/fesm2022/anycms-a2ui-angular.mjs"}},"scripts":{"test":"vitest run","build":"ng-packagr -c tsconfig.lib.json","pretest":"ng-packagr -c tsconfig.lib.json","typecheck":"ng-packagr -c tsconfig.lib.json","test:watch":"vitest"},"_npmUser":{"name":"wuliangdi","email":"wu@liangdi.me"},"_resolved":"/tmp/e862a8e86455cdd06d05072e10b4aebc/anycms-a2ui-angular-0.1.1.tgz","_integrity":"sha512-GohDZpNw7UnrtwnrjQdMxdDGuTQp8bzuAAsLxtlZzjaFyVekBWSEzJ8fEJijQvpZMIGrTv88R5qD+umm3q6Lfg==","repository":{"url":"git+https://github.com/anycms/a2ui.git","type":"git","directory":"packages/a2ui-angular"},"_npmVersion":"10.9.2","description":"Angular renderer for A2UI v1.0.","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"tslib":"^2.6.0","@anycms/a2ui-core":"0.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^25.0.1","vitest":"^2.1.8","ng-packagr":"^21.0.0","typescript":"5.9.3","@angular/core":"^21.0.0","@angular/common":"^21.0.0","@angular/compiler":"^21.0.0","@angular/compiler-cli":"^21.0.0","@angular/platform-browser":"^21.0.0","@angular/platform-browser-dynamic":"^21.0.0"},"peerDependencies":{"rxjs":"^7.8.0","@angular/core":"^21.0.0"},"_npmOperationalInternal":{"tmp":"tmp/a2ui-angular_0.1.1_1781596355358_0.24659450499846236","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@anycms/a2ui-angular","version":"0.2.0","description":"Angular renderer for A2UI v1.0.","license":"MIT","author":{"name":"Liangdi","email":"wu@liangdi.me"},"homepage":"https://github.com/anycms/a2ui","repository":{"type":"git","url":"git+https://github.com/anycms/a2ui.git","directory":"packages/a2ui-angular"},"bugs":{"url":"https://github.com/anycms/a2ui/issues"},"keywords":["a2ui","anycms","generative-ui","angular","renderer","ai-ui"],"publishConfig":{"access":"public"},"type":"module","sideEffects":false,"module":"dist/fesm2022/anycms-a2ui-angular.mjs","types":"dist/types/anycms-a2ui-angular.d.ts","exports":{".":{"types":"./dist/types/anycms-a2ui-angular.d.ts","default":"./dist/fesm2022/anycms-a2ui-angular.mjs"}},"peerDependencies":{"@angular/core":"^21.0.0","rxjs":"^7.8.0"},"dependencies":{"tslib":"^2.6.0","@anycms/a2ui-core":"0.2.0"},"devDependencies":{"@angular/common":"^21.0.0","@angular/compiler":"^21.0.0","@angular/compiler-cli":"^21.0.0","@angular/core":"^21.0.0","@angular/platform-browser":"^21.0.0","@angular/platform-browser-dynamic":"^21.0.0","jsdom":"^25.0.1","ng-packagr":"^21.0.0","typescript":"5.9.3","vitest":"^2.1.8"},"scripts":{"build":"ng-packagr -c tsconfig.lib.json","pretest":"ng-packagr -c tsconfig.lib.json","test":"vitest run","test:watch":"vitest","typecheck":"ng-packagr -c tsconfig.lib.json"},"_id":"@anycms/a2ui-angular@0.2.0","_integrity":"sha512-I1e/1RJPAj3i3IfviysMdiXFtblPGchmMAAxZZV5HZtTPWB8C4UT+Kxwq2RQzpM6sEfJ9vMqrbY0PmX5pfy05g==","_resolved":"/tmp/442c78240b07835e2b43e2768065836b/anycms-a2ui-angular-0.2.0.tgz","_from":"file:anycms-a2ui-angular-0.2.0.tgz","_nodeVersion":"25.1.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-I1e/1RJPAj3i3IfviysMdiXFtblPGchmMAAxZZV5HZtTPWB8C4UT+Kxwq2RQzpM6sEfJ9vMqrbY0PmX5pfy05g==","shasum":"6c52187e4143f32f1039b935c37157d25cdbff9e","tarball":"https://registry.npmjs.org/@anycms/a2ui-angular/-/a2ui-angular-0.2.0.tgz","fileCount":21,"unpackedSize":242729,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCz633cm0+cvdsZ4syEEH3yt/oX0BSRxq3BMSzPWKznngIgbTUbaPPGa7hshvUaHH7+TtBbTVR1EjZPXXiWNg8B9Fc="}]},"_npmUser":{"name":"wuliangdi","email":"wu@liangdi.me"},"directories":{},"maintainers":[{"name":"wuliangdi","email":"wu@liangdi.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/a2ui-angular_0.2.0_1781606787629_0.5472744216619065"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-16T07:52:35.153Z","modified":"2026-06-16T10:46:27.920Z","0.1.1":"2026-06-16T07:52:35.493Z","0.2.0":"2026-06-16T10:46:27.792Z"},"bugs":{"url":"https://github.com/anycms/a2ui/issues"},"author":{"name":"Liangdi","email":"wu@liangdi.me"},"license":"MIT","homepage":"https://github.com/anycms/a2ui","keywords":["a2ui","anycms","generative-ui","angular","renderer","ai-ui"],"repository":{"type":"git","url":"git+https://github.com/anycms/a2ui.git","directory":"packages/a2ui-angular"},"description":"Angular renderer for A2UI v1.0.","maintainers":[{"name":"wuliangdi","email":"wu@liangdi.me"}],"readme":"# @anycms/a2ui-angular\n\nAn **Angular 21 renderer** for [A2UI](https://github.com/anycms/a2ui) v1.0. It renders the same server-driven A2UI message stream as the React and Vue renderers, but with native standalone Angular components — fully **zoneless** and **signal-driven**.\n\nIt is a peer of `@anycms/a2ui-react`, `@anycms/a2ui-vue`, and `@anycms/a2ui-dom`. The A2UI binders, reactive runtime, and message processor are reused unchanged from `@anycms/a2ui-core`; only the adapter (`A2uiBoundComponent` / `<a2ui-surface>` / `<a2ui-node>`) and the 18 component Views are reimplemented for Angular.\n\n## Why\n\nDrop-in A2UI rendering for Angular apps — no React or Vue runtime, no manual DOM. Each bound node subscribes to its own reactive props stream from core and writes it into a signal, so under zoneless change detection data-model updates repaint the UI granularly, inputs preserve focus across re-renders, and `Tabs`/`Modal` preserve local UI state (held in component signals).\n\n## Install\n\n```bash\npnpm add @anycms/a2ui-angular @anycms/a2ui-core\n```\n\n`@angular/core` (`^21`) and `rxjs` are peer dependencies. Zoneless change detection is the default — `zone.js` is **not** required.\n\n## Usage\n\n```ts\nimport { Component } from '@angular/core';\nimport { A2uiSurfaceComponent } from '@anycms/a2ui-angular';\n// `surface` is a SurfaceModel produced by MessageProcessor.processMessages(...)\n\n@Component({\n  selector: 'app-demo',\n  standalone: true,\n  imports: [A2uiSurfaceComponent],\n  template: `<a2ui-surface [surface]=\"surface\" />`,\n})\nexport class DemoComponent {\n  surface = /* a SurfaceModel */;\n}\n```\n\n`<a2ui-surface [surface] [catalog?] [registry?]>` renders the `root` component of a surface and provides the surface/catalog/registry to the tree. Each bound node self-subscribes to structural events (`onCreated`/`onDeleted`), so a component type-change rebuilds its binding and a late-arriving child mounts — without a top-level force-rerender.\n\nThe default registry (`basicAngularComponents`) renders all 18 Basic Catalog components. Pass a custom registry to override individual components:\n\n```ts\nimport { createAngularComponent, basicAngularComponents } from '@anycms/a2ui-angular';\nimport { textBinder } from '@anycms/a2ui-core';\n\nconst registry = new Map(basicAngularComponents);\nregistry.set('Text', createAngularComponent(textBinder, MyTextView));\n```\n\nA View is a standalone `@Component` with `props` / `ctx` **signal inputs** (optional for a leaf, read with `props()?.…`). For local UI state (`Tabs`, `Modal`), hold a component `signal`:\n\n```ts\nimport { ChangeDetectionStrategy, Component, computed, input, signal } from '@angular/core';\nimport type { TextProps } from '@anycms/a2ui-core';\nimport { createAngularComponent, type ComponentViewProps } from '@anycms/a2ui-angular';\n\n@Component({\n  selector: 'my-text',\n  standalone: true,\n  template: `<p class=\"a2ui-leaf\">{{ props()?.text }}</p>`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MyTextViewComponent {\n  readonly props = input<TextProps>();\n  // ComponentViewProps<TextProps> documents the { props, ctx } shape.\n}\n\nexport const registry = new Map([['Text', createAngularComponent(textBinder, MyTextViewComponent)]]);\n```\n\n## How it maps to the React / Vue adapters\n\n| React / Vue | Angular |\n| --- | --- |\n| `createReactComponent` / `createVueComponent` | `createAngularComponent(binder, view)` (pairing); binding done in `A2uiBoundComponent` |\n| `<A2uiSurface>` provides context | `<a2ui-surface>` provides via `A2UI_SURFACE` `InjectionToken` |\n| `useState` / `shallowRef` for the props stream | a `signal` updated from `propsStream.subscribe` in `A2uiBoundComponent` |\n| `useState` / local `ref` in `Tabs`/`Modal` | a component `signal` |\n| reactivity via `propsStream` subscription | same, bridged to signals (zoneless CD) |\n\n## Styling\n\nMirrors the React/Vue vanilla preset: inline styles with the leaf-margin strategy (leaves carry 8px; containers flush) and semantic class hooks (`a2ui-surface`, `a2ui-row`, `a2ui-column`, `a2ui-list`, `a2ui-leaf`, `a2ui-modal`). No CSS framework required.\n\n## License\n\nMIT © Liangdi\n","readmeFilename":"README.md"}