Skip to content

feat(angular): add @json-render/angular renderer - #310

Closed
tomzohar wants to merge 6 commits into
vercel-labs:mainfrom
tomzohar:add-angular-renderer
Closed

feat(angular): add @json-render/angular renderer#310
tomzohar wants to merge 6 commits into
vercel-labs:mainfrom
tomzohar:add-angular-renderer

Conversation

@tomzohar

@tomzohar tomzohar commented Jul 21, 2026

Copy link
Copy Markdown

Summary

Adds a new first-party Angular renderer, @json-render/angular , at feature
parity with the existing React, Vue, and Solid renderers. The package
mirrors
the baseline public API surface exactly (React = Vue = Solid share one
contract;
this package holds it too) and ships as an idiomatic modern Angular library
(standalone components, signals, inject() ).

No new runtime dependencies are added for consumers.

Motivation

json-render supports React, Vue, Solid, and Svelte. Angular is the
remaining
major framework without a first-party renderer. This PR closes that gap so
Angular apps can render the same JSON UI specs with the same capabilities
(state, visibility, actions, validation, repeat, streaming) as every other
supported framework.

What's included

New package: packages/angular ( @json-render/angular , v0.19.0)

• Build: ng-packagr https://github.com/ng-packagr/ng-packagr (Angular
Package Format), consistent with the Svelte package's use of svelte-package
rather than tsup . Two entry points ( . and ./schema ), full AOT.
• Angular version: built against Angular 21 / ng-packagr 21 to stay within
the workspace TypeScript ~5.9 pin (Angular 22's compiler requires TS >= 6.0 ,
which would be a much more invasive workspace-wide bump). Consumer
peerDependencies are kept broad: @angular/* "^20 || ^21 || ^22" .
• Public API parity with the baseline:
• schema , AngularSchema , AngularSpec (+ Spec , StateStore ,
createStateStore re-exports)
• JsonRenderComponent , ComponentRegistry , defineRegistry
• provideJsonRender , createRenderer , JsonRendererComponent
• JSON_RENDER_* DI tokens
• SpecStateService , VisibilityService , ActionDispatcherService ,
ValidationService , RepeatScopeService , ChildrenOutletDirective
• JsonRenderConfirmDialogDirective (headless) plus an out-of-the-box
styled
ConfirmDialog component
• boundProp / injectBoundProp
• streaming: flatToTree / buildSpecFromParts / getTextFromParts ,
injectUIStream / injectChatUI / injectJsonRenderMessage
• core re-exports ( defineCatalog , getByPath , setByPath , check ,
createDirectiveRegistry , defineDirective , resolvePropValue , + types)
• Tests: colocated *.test.ts suites (8 files, including TestBed component
tests) run through an isolated Vitest pipeline powered by
@analogjs/vite-plugin-angular , invoked via pnpm test:angular .

Parity gap fixes (behavior verified against the baseline)

• validateForm writes { valid, errors } to params.statePath ??
'/formValidation'
and does not throw; added to schema.builtInActions .
• repeat $item filter uses core splitRepeatVisibility to separate the
container visibility gate from the per-item filter, preserving item indices.
• external StateStore support via [store] input and
SpecStateService.connectStore/disconnectStore .
• onStateChange emits Array<{ path, value }> deltas.
• default rules now include the two previously missing rules
( required-children , filtered lists).

Root / shared changes

• package.json : adds a test:angular script (no Angular devDeps at root;
they
live in the package).
• vitest.config.mts : excludes packages/angular/** . Angular requires its
own
compiler pipeline ( @analogjs/vite-plugin-angular ), which is incompatible
with
the shared React/Svelte/Solid transforms; putting it in the root config
breaks
those suites.
• pnpm-workspace.yaml : marks transitive native-build deps
( @parcel/watcher , lmdb , msgpackr-extract ) as non-building. These come
in
via the Angular test tooling; they are only needed for watch/dev, not
build/test.
• README.md : packages-table row, install line, and an Angular renderer
section.
• pnpm-lock.yaml : updated for the new Angular devDependencies.
• skills/angular/SKILL.md : agent skill for the Angular renderer.

Validation

Run on Node 24 / pnpm:

• pnpm turbo run build --filter='./packages/*' — all library packages
build,
including @json-render/angular via ng-packagr (both entry points, full
AOT).
• pnpm test — green (930 tests). The root config now excludes
packages/angular .
• pnpm test:angular — green (all 8 Angular test files, including TestBed
component tests and the B2/B3/M5 behavior tests).
• pnpm --filter @json-render/angular typecheck — clean.

│ Note: the CI test job builds packages/* and then runs pnpm test . To
run
│ the
│ Angular suite in CI, pnpm test:angular must be added to the workflow
(see
│ Follow-ups).

Follow-ups (deferred, intentionally out of scope for this PR)

  1. CI: add pnpm test:angular to .github/workflows/ci.yml so the Angular
    suite runs in CI (today only pnpm test runs, which excludes this package).
  2. Docs site: apps/web API page + navigation/title/docs-chat wiring for
    the
    Angular renderer.
  3. Commit signing: this commit is unsigned; can be revisited if/when SSH
    signing is set up.

Notes for reviewers

• ng-packagr owns the published package.json (generates dist/package.json
);
the source package.json intentionally does not hand-write
exports / module / typings .
• This is a pnpm workspace ( npm install fails on workspace:* ); Node >=24 ,
pnpm >=11 .

Add a new first-party Angular renderer package at feature parity with the
React, Vue, and Solid baselines. The public API mirrors the baseline export
surface exactly.

Package (packages/angular):
- Built with ng-packagr (Angular Package Format), matching the Svelte
  package's use of svelte-package rather than tsup. Zero added consumer
  runtime dependencies.
- Public API parity: schema/AngularSchema/AngularSpec, JsonRenderComponent,
  ComponentRegistry, defineRegistry, provideJsonRender, createRenderer,
  JsonRendererComponent, JSON_RENDER_* tokens, SpecStateService,
  VisibilityService, ActionDispatcherService, ValidationService,
  RepeatScopeService, ChildrenOutletDirective, confirm-dialog directive +
  styled ConfirmDialog component, boundProp/injectBoundProp, streaming
  parts helpers, injectUIStream/injectChatUI/injectJsonRenderMessage, and
  core re-exports.
- Angular 21 (ng-packagr 21) to stay within the workspace TypeScript ~5.9
  pin; consumer peerDependencies kept broad (^20 || ^21 || ^22).
- Idiomatic modern Angular: standalone components, signals, inject().
- Colocated *.test.ts suites run via an isolated Vitest pipeline
  (@analogjs/vite-plugin-angular) using pnpm test:angular.

Parity gap fixes: validateForm writes {valid,errors} without throwing (B2),
repeat $item filtering via core splitRepeatVisibility (B3), external
StateStore support (M4), onStateChange delta emission (M5), and the missing
default rules (M6).

Root/shared changes:
- package.json: add test:angular script.
- vitest.config.mts: exclude packages/angular (Angular needs its own
  compiler pipeline; incompatible with the shared React/Svelte/Solid
  transforms).
- pnpm-workspace.yaml: mark native-build transitive deps
  (@parcel/watcher, lmdb, msgpackr-extract) as non-building.
- README.md: packages table row, install line, and Angular section.
- pnpm-lock.yaml: Angular devDependencies.

Also adds skills/angular/SKILL.md.

Follow-ups (deferred): wire pnpm test:angular into CI, apps/web docs-site
integration, and optional commit signing.
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

@tomzohar is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@socket-security

socket-security Bot commented Jul 21, 2026

Copy link
Copy Markdown

tomzohar added 5 commits July 22, 2026 15:07
- Add pnpm test:angular step to CI test job so Angular tests run in CI
- Remove tslib from dependencies (importHelpers: false)
- Align @angular/build devDep to 21.2.18 (match other Angular packages)
…ch errors

- Refactor onStateChange from input() to output() (stateChange event)
- Add .catch(onEventDispatchError) to fire-and-forget dispatcher calls
- Remove 20+ core re-exports from public API (consumers import from @json-render/core)
- Add cross-renderer naming map to README
- Update onStateChange docs to (stateChange) output syntax
- Update defineCatalog import to @json-render/core in README and SKILL.md
Exercises every package feature: spec rendering, state binding,
repeat/filtered lists, visibility, actions, validation, confirmation
dialogs, watchers, streaming helpers, external state store, and
(stateChange) output.
@tomzohar tomzohar closed this Aug 3, 2026
@tomzohar
tomzohar deleted the add-angular-renderer branch August 3, 2026 10:23
@shteynu

shteynu commented Aug 28, 2026

Copy link
Copy Markdown

For anyone finding this closed PR while looking for Angular support: a standalone Angular renderer is now available —

Same renderer contract as the official React/Vue/Solid/Svelte packages on top of @json-render/core 0.20 (flat specs, $state/$cond/$template expressions, two-way bindings, visibility, repeat scopes, slots, actions with confirm flows, SpecStream patch streaming), built on Angular signals, zoneless-friendly, Angular ≥ 20. There's also ngx-json-render-material, a 28-component Angular Material catalog. Also mentioned in #244.

@tomzohar — if you're still interested in json-render + Angular, feedback and contributions are very welcome.

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.

2 participants