ngx-json-render 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/ngx-json-render)](https://www.npmjs.com/package/ngx-json-render) [![CI](https://github.com/shteynu/ngx-json-render/actions/workflows/ci.yml/badge.svg)](https://github.com/shteynu/ngx-json-render/actions/workflows/ci.yml) [![license](https://img.shields.io/npm/l/ngx-json-render)](https://github.com/shteynu/ngx-json-render/blob/main/LICENSE)
4
4
 
5
- Angular renderer for [json-render](https://github.com/vercel-labs/json-render) — give an LLM a catalog of your components, stream back a JSON spec, and render it as real Angular components. No `innerHTML`, no `eval`, no framework lock-in on the wire format.
5
+ Generative UI for Angular: a renderer for [json-render](https://github.com/vercel-labs/json-render). Give an LLM a catalog of your components, stream back a JSON spec, and render it as real Angular components. No `innerHTML`, no `eval`, no framework lock-in on the wire format.
6
6
 
7
7
  Built on `@json-render/core` (the same spec format, expressions, state store, actions, and streaming compiler used by the React, Vue, Solid, and Svelte renderers) and idiomatic modern Angular: standalone components, signals, `OnPush` everywhere, and zoneless — no `NgZone`, no Zone.js.
8
8
 
@@ -57,12 +57,14 @@ npx skills add shteynu/ngx-json-render --skill ngx-json-render
57
57
 
58
58
  The source is [`skills/ngx-json-render/SKILL.md`](https://github.com/shteynu/ngx-json-render/blob/main/skills/ngx-json-render/SKILL.md);
59
59
  the Material catalog has one too (`--skill ngx-json-render-material`).
60
+ An agent that reads [llms.txt](https://llmstxt.org) instead can start from
61
+ <https://shteynu.github.io/ngx-json-render/llms.txt>.
60
62
 
61
63
  ## The shortest path: a ready-made catalog
62
64
 
63
65
  Writing a catalog is the honest first step, but you do not have to take it to
64
66
  see a spec render. [`ngx-json-render-material`](https://www.npmjs.com/package/ngx-json-render-material)
65
- ships 29 Angular Material components already registered, so a generated spec
67
+ ships 33 Angular Material components already registered, so a generated spec
66
68
  renders with nothing else wired up:
67
69
 
68
70
  ```bash
@@ -119,7 +121,7 @@ against `@hashbrownai/angular` 0.6.1, as published on 2026-09-30:
119
121
  | What the model emits | A json-render spec, streamed as RFC 6902 patches — the format the React, Vue, Svelte and Solid renderers read, so a catalog and a spec move between frameworks unchanged | Hashbrown's own JSON, generated against a schema built from the components you expose; read by Hashbrown's Angular and React clients |
120
122
  | Server | Anything that streams text: the [AI SDK](https://ai-sdk.dev) in a few lines, or your own endpoint; `catalog.prompt()` writes the system prompt | An [AG-UI](https://docs.ag-ui.com) endpoint, built with Hashbrown's adapters (OpenAI, Anthropic, Google, Azure, Bedrock, Ollama) or your own mapping |
121
123
  | Angular | 20, 21 and 22, each tested in CI | 22 only since 0.6 (0.5 supported 20 and 21) |
122
- | Components | Your own, or 29 ready-made Angular Material ones ([`ngx-json-render-material`](https://www.npmjs.com/package/ngx-json-render-material)) | Your own (`exposeComponent`, UI kits) |
124
+ | Components | Your own, or 33 ready-made Angular Material ones ([`ngx-json-render-material`](https://www.npmjs.com/package/ngx-json-render-material)) | Your own (`exposeComponent`, UI kits) |
123
125
  | Beyond rendering | Rendering-focused: state and two-way bindings in the spec, actions, visibility, repeat, watch, confirmation dialogs | An agent toolkit: client-side tools, a QuickJS sandbox for model-written code, shared agent state, interrupts, streaming Markdown |
124
126
  | License | Apache-2.0 | MIT |
125
127
 
@@ -250,6 +252,38 @@ export class Page {
250
252
  }
251
253
  ```
252
254
 
255
+ ### Defaults for the whole app
256
+
257
+ A chat renders a spec in every message, and binding the same registry and handlers on each one gets old. `provideJsonRender` sets them once:
258
+
259
+ ```ts
260
+ bootstrapApplication(App, {
261
+ providers: [
262
+ provideJsonRender(() => {
263
+ const orders = inject(OrderService); // the function form runs in an injection context
264
+ return {
265
+ registry,
266
+ catalog,
267
+ handlers: { cancelOrder: (params) => orders.cancel(params['id']) },
268
+ };
269
+ }),
270
+ ],
271
+ });
272
+ ```
273
+
274
+ ```html
275
+ <json-render [spec]="m.spec" />
276
+ ```
277
+
278
+ Every option input can be provided: `registry`, `fallback`, `validate`, `renderLimits`, `catalog`, `handlers`, `onAction`, `navigate`, `validationFunctions`, `functions` and `directives`. Per-instance inputs (`spec`, `loading`, `state`, `store`) cannot. The rules:
279
+
280
+ - An input bound on the element wins over the provided value. One left `null` or `undefined` falls through to it.
281
+ - `handlers`, `functions`, `validationFunctions` and `directives` merge by name instead, the element's entry winning a name both define. A chat can provide app-wide handlers and still add one for a single message.
282
+ - Everything else replaces. A `registry` belongs to its catalog, so two are never mixed behind your back; to combine them, spread them yourself (`{ ...registry, ...extraRegistry }`).
283
+ - It works in application, route and component `providers`. A provider below another extends it by the same rules.
284
+
285
+ With no registry bound and none provided, the renderer throws, naming both ways to supply one.
286
+
253
287
  ## Streaming a UI from an LLM
254
288
 
255
289
  Specs stream as JSONL patch lines (RFC 6902). Render partial specs as they arrive — the renderer tolerates missing elements while `loading` is true:
@@ -391,15 +425,16 @@ import { JsonRenderer, injectChatUI } from 'ngx-json-render';
391
425
  @for (m of chat.messages(); track m.id) {
392
426
  <p>{{ m.text }}</p>
393
427
  @if (m.spec) {
394
- <json-render [spec]="m.spec" [registry]="registry" />
428
+ <json-render [spec]="m.spec" />
395
429
  }
396
430
  }
397
431
  <button (click)="chat.send('show me revenue for the quarter')">Ask</button>
398
432
  `,
399
433
  })
400
434
  export class ChatPage {
435
+ // The registry comes from provideJsonRender({ registry }) in the app's
436
+ // providers: see "Defaults for the whole app".
401
437
  readonly chat = injectChatUI({ api: '/api/chat' });
402
- readonly registry = registry;
403
438
  }
404
439
  ```
405
440
 
@@ -965,7 +1000,26 @@ rather than the one holding session, entitlement or billing state.
965
1000
  **A spec chooses the navigation target.** `onSuccess: { navigate }` passes its
966
1001
  string to the `navigate` callback you provide, verbatim. Treat it as untrusted:
967
1002
  match it against known routes, and never hand it to `window.location` or
968
- `router.navigateByUrl` unchecked.
1003
+ `router.navigateByUrl` unchecked. `ngx-json-render/router` does the checking
1004
+ for an app on the Angular `Router`:
1005
+
1006
+ ```ts
1007
+ import { injectRouterNavigate } from 'ngx-json-render/router';
1008
+
1009
+ provideJsonRender(() => ({
1010
+ registry,
1011
+ navigate: injectRouterNavigate({ allow: ['/thanks', /^\/orders\/\d+$/] }),
1012
+ }));
1013
+ ```
1014
+
1015
+ It passes a path to `router.navigateByUrl` only when `allow` lets it through
1016
+ (strings match the path exactly, before any `?` or `#`; a `RegExp` is tested
1017
+ against it; a function decides). `allow` is required, because only the app
1018
+ knows which of its routes a generated UI may open. Whatever `allow` says, a
1019
+ path that does not start with a single `/` is refused: no other origin, no
1020
+ `javascript:` or other scheme, no relative path, no backslash or control
1021
+ character. A refused path, or a navigation the router rejects, is reported
1022
+ with `console.warn` and goes nowhere.
969
1023
 
970
1024
  **A spec cannot render forever.** Two elements naming each other as children,
971
1025
  or one naming itself, would recurse until the tab died. The renderer refuses to
@@ -1013,6 +1067,8 @@ Components: `JsonRenderer` (`<json-render>`), `JrChildren`, `JrConfirmDialog`, `
1013
1067
 
1014
1068
  Injectables/helpers: `injectRenderContext`, `injectElementKey`, `injectRepeatScope`, `injectStateStore`, `injectStateValue`, `injectStateBinding`, `injectBoundProp`, `injectActions`, `injectAction`, `injectValidation`, `injectFieldValidation`, `injectUIStream`, `injectChatUI`, `injectDevtoolsActive`, `injectConfirmContext`, `jsonRenderMessage`, `isActionCancelled`, `checkSpec`.
1015
1069
 
1070
+ App-wide defaults: `provideJsonRender`, the `JSON_RENDER_CONFIG` token it fills, and the type `JsonRenderConfig`.
1071
+
1016
1072
  Tokens: `JR_CONFIRM_DIALOG` (replace the confirmation dialog), `JR_CONFIRM_LABELS` (its two words), `CONFIRM_CONTEXT`, `RENDER_CONTEXT`, `REPEAT_SCOPE`.
1017
1073
 
1018
1074
  Spec checking: `checkSpec`, `formatSpecCheckIssues`, and the types
@@ -1031,6 +1087,8 @@ Schema alone (`ngx-json-render/schema`): `schema`, `AngularSchema`, `AngularSpec
1031
1087
 
1032
1088
  MCP Apps (`ngx-json-render/mcp`): `injectJsonRenderApp`, `parseSpecFromToolResult`, `messageText`, and the types `JsonRenderApp`, `JsonRenderAppOptions`. Needs the optional peers `@modelcontextprotocol/ext-apps` and `@modelcontextprotocol/sdk`.
1033
1089
 
1090
+ Router (`ngx-json-render/router`): `injectRouterNavigate`, and the type `RouterNavigateOptions`. Needs the optional peer `@angular/router`, which an Angular app on the router already has.
1091
+
1034
1092
  Devtools (`ngx-json-render/devtools`): `JsonRenderDevtools` (`<json-render-devtools>`), and the types `DevtoolsEvent`, `PanelPosition`. Needs the optional peer `@json-render/devtools`.
1035
1093
 
1036
1094
  Testing (`ngx-json-render/testing`): `renderSpec`, `renderComponent`, `recordedTransport`, `specStream`, `usageLine`.
@@ -1042,7 +1100,7 @@ Everything from `@json-render/core` (types, `createStateStore`, `nestedToFlat`,
1042
1100
  | Input | Type | Purpose |
1043
1101
  | --------------------- | ------------------------------------ | ------------------------------------------------------- |
1044
1102
  | `spec` | `Spec \| null` | The UI spec (may be partial while streaming) |
1045
- | `registry` | `ComponentRegistry` | Catalog type → Angular component |
1103
+ | `registry` | `ComponentRegistry` | Catalog type → component; required unless provided |
1046
1104
  | `loading` | `boolean` | Suppress missing-element warnings while streaming |
1047
1105
  | `fallback` | `Type<unknown>` | Component for unknown types |
1048
1106
  | `validate` | `'off' \| 'warn' \| 'strict'` | Check the settled spec's structure (default `'off'`) |
@@ -1059,6 +1117,8 @@ Everything from `@json-render/core` (types, `createStateStore`, `nestedToFlat`,
1059
1117
 
1060
1118
  Output: `(stateChange)` — batched `{ path, value }[]` in uncontrolled mode.
1061
1119
 
1120
+ Every input but `spec`, `loading`, `state` and `store` can come from `provideJsonRender` instead; see [Defaults for the whole app](#defaults-for-the-whole-app).
1121
+
1062
1122
  ## License
1063
1123
 
1064
1124
  Apache-2.0
@@ -238,10 +238,10 @@ class JsonRenderDevtools {
238
238
  this.events = null;
239
239
  });
240
240
  }
241
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: JsonRenderDevtools, deps: [], target: i0.ɵɵFactoryTarget.Component });
242
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.22", type: JsonRenderDevtools, isStandalone: true, selector: "json-render-devtools", inputs: { renderer: { classPropertyName: "renderer", publicName: "renderer", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, chat: { classPropertyName: "chat", publicName: "chat", isSignal: true, isRequired: false, transformFunction: null }, initialOpen: { classPropertyName: "initialOpen", publicName: "initialOpen", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, hotkey: { classPropertyName: "hotkey", publicName: "hotkey", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, reserveSpace: { classPropertyName: "reserveSpace", publicName: "reserveSpace", isSignal: true, isRequired: false, transformFunction: null }, allowDockToggle: { classPropertyName: "allowDockToggle", publicName: "allowDockToggle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { event: "event" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
241
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderDevtools, deps: [], target: i0.ɵɵFactoryTarget.Component });
242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.25", type: JsonRenderDevtools, isStandalone: true, selector: "json-render-devtools", inputs: { renderer: { classPropertyName: "renderer", publicName: "renderer", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null }, catalog: { classPropertyName: "catalog", publicName: "catalog", isSignal: true, isRequired: false, transformFunction: null }, chat: { classPropertyName: "chat", publicName: "chat", isSignal: true, isRequired: false, transformFunction: null }, initialOpen: { classPropertyName: "initialOpen", publicName: "initialOpen", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, hotkey: { classPropertyName: "hotkey", publicName: "hotkey", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, reserveSpace: { classPropertyName: "reserveSpace", publicName: "reserveSpace", isSignal: true, isRequired: false, transformFunction: null }, allowDockToggle: { classPropertyName: "allowDockToggle", publicName: "allowDockToggle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { event: "event" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
243
243
  }
244
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: JsonRenderDevtools, decorators: [{
244
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JsonRenderDevtools, decorators: [{
245
245
  type: Component,
246
246
  args: [{
247
247
  selector: 'json-render-devtools',
@@ -0,0 +1,71 @@
1
+ import { inject } from '@angular/core';
2
+ import { Router } from '@angular/router';
3
+
4
+ /**
5
+ * A `navigate` for `<json-render>` that hands a spec's
6
+ * `onSuccess: { navigate }` path to the Angular `Router`, but only a path
7
+ * inside the app that `allow` lets through. Anything else is refused with a
8
+ * warning and goes nowhere.
9
+ *
10
+ * Call it in an injection context — in the function form of
11
+ * `provideJsonRender`, or in a field initializer:
12
+ *
13
+ * ```ts
14
+ * provideJsonRender(() => ({
15
+ * registry,
16
+ * navigate: injectRouterNavigate({ allow: ['/thanks', /^\/orders\/\d+$/] }),
17
+ * }));
18
+ * ```
19
+ *
20
+ * Whatever `allow` says, a path is refused unless it starts with a single
21
+ * `/`: no other origin (`https://…`, `//host`), no scheme (`javascript:…`),
22
+ * no path relative to wherever the user happens to be. A backslash or a
23
+ * control character refuses it too, since browsers read `/\host` as
24
+ * `//host`.
25
+ */
26
+ function injectRouterNavigate(options) {
27
+ const router = inject(Router);
28
+ const allowed = toPredicate(options.allow);
29
+ return (path) => {
30
+ if (!isAppPath(path)) {
31
+ console.warn(`[ngx-json-render] Refused to navigate to ${JSON.stringify(path)}: a spec may only navigate to a path inside the app, starting with a single "/".`);
32
+ return;
33
+ }
34
+ const pathname = path.split(/[?#]/, 1)[0];
35
+ if (!allowed(pathname)) {
36
+ console.warn(`[ngx-json-render] Refused to navigate to "${path}": "${pathname}" is not in the allow list given to injectRouterNavigate.`);
37
+ return;
38
+ }
39
+ router.navigateByUrl(path).catch((error) => {
40
+ console.warn(`[ngx-json-render] Navigation to "${path}" failed.`, error);
41
+ });
42
+ };
43
+ }
44
+ function isAppPath(path) {
45
+ return (typeof path === 'string' &&
46
+ /^\/(?![/\\])/.test(path) &&
47
+ !/[\\\u0000-\u001f\u007f]/.test(path));
48
+ }
49
+ function toPredicate(allow) {
50
+ if (typeof allow === 'function')
51
+ return allow;
52
+ return (path) => allow.some((rule) => {
53
+ if (typeof rule === 'string')
54
+ return rule === path;
55
+ // A global or sticky RegExp keeps `lastIndex` between calls; reset it so
56
+ // one rule answers the same way for the same path every time.
57
+ rule.lastIndex = 0;
58
+ return rule.test(path);
59
+ });
60
+ }
61
+
62
+ /*
63
+ * Public API Surface of ngx-json-render/router
64
+ */
65
+
66
+ /**
67
+ * Generated bundle index. Do not edit.
68
+ */
69
+
70
+ export { injectRouterNavigate };
71
+ //# sourceMappingURL=ngx-json-render-router.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-json-render-router.mjs","sources":["../../../projects/ngx-json-render/router/src/router-navigate.ts","../../../projects/ngx-json-render/router/src/public-api.ts","../../../projects/ngx-json-render/router/src/ngx-json-render-router.ts"],"sourcesContent":["import { inject } from '@angular/core';\nimport { Router } from '@angular/router';\n\n/** Which paths a spec may send the app to. */\nexport interface RouterNavigateOptions {\n /**\n * The paths a spec may navigate to. A string must equal the path exactly; a\n * `RegExp` is tested against it; a function decides on its own. The path is\n * what comes before any `?` or `#`, so a query string or fragment neither\n * helps nor hurts a match, and is passed on to the router as written.\n *\n * Required: a spec is model output, and the app is what knows which of its\n * routes a generated UI has any business opening.\n */\n readonly allow: readonly (string | RegExp)[] | ((path: string) => boolean);\n}\n\n/**\n * A `navigate` for `<json-render>` that hands a spec's\n * `onSuccess: { navigate }` path to the Angular `Router`, but only a path\n * inside the app that `allow` lets through. Anything else is refused with a\n * warning and goes nowhere.\n *\n * Call it in an injection context — in the function form of\n * `provideJsonRender`, or in a field initializer:\n *\n * ```ts\n * provideJsonRender(() => ({\n * registry,\n * navigate: injectRouterNavigate({ allow: ['/thanks', /^\\/orders\\/\\d+$/] }),\n * }));\n * ```\n *\n * Whatever `allow` says, a path is refused unless it starts with a single\n * `/`: no other origin (`https://…`, `//host`), no scheme (`javascript:…`),\n * no path relative to wherever the user happens to be. A backslash or a\n * control character refuses it too, since browsers read `/\\host` as\n * `//host`.\n */\nexport function injectRouterNavigate(\n options: RouterNavigateOptions,\n): (path: string) => void {\n const router = inject(Router);\n const allowed = toPredicate(options.allow);\n return (path) => {\n if (!isAppPath(path)) {\n console.warn(\n `[ngx-json-render] Refused to navigate to ${JSON.stringify(path)}: a spec may only navigate to a path inside the app, starting with a single \"/\".`,\n );\n return;\n }\n const pathname = path.split(/[?#]/, 1)[0];\n if (!allowed(pathname)) {\n console.warn(\n `[ngx-json-render] Refused to navigate to \"${path}\": \"${pathname}\" is not in the allow list given to injectRouterNavigate.`,\n );\n return;\n }\n router.navigateByUrl(path).catch((error: unknown) => {\n console.warn(`[ngx-json-render] Navigation to \"${path}\" failed.`, error);\n });\n };\n}\n\nfunction isAppPath(path: unknown): path is string {\n return (\n typeof path === 'string' &&\n /^\\/(?![/\\\\])/.test(path) &&\n !/[\\\\\\u0000-\\u001f\\u007f]/.test(path)\n );\n}\n\nfunction toPredicate(\n allow: RouterNavigateOptions['allow'],\n): (path: string) => boolean {\n if (typeof allow === 'function') return allow;\n return (path) =>\n allow.some((rule) => {\n if (typeof rule === 'string') return rule === path;\n // A global or sticky RegExp keeps `lastIndex` between calls; reset it so\n // one rule answers the same way for the same path every time.\n rule.lastIndex = 0;\n return rule.test(path);\n });\n}\n","/*\n * Public API Surface of ngx-json-render/router\n */\n\nexport {\n injectRouterNavigate,\n type RouterNavigateOptions,\n} from './router-navigate';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;AAiBA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,oBAAoB,CAClC,OAA8B,EAAA;AAE9B,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;IAC1C,OAAO,CAAC,IAAI,KAAI;AACd,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;AACpB,YAAA,OAAO,CAAC,IAAI,CACV,CAAA,yCAAA,EAA4C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,gFAAA,CAAkF,CACnJ;YACD;QACF;AACA,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAA,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YACtB,OAAO,CAAC,IAAI,CACV,CAAA,0CAAA,EAA6C,IAAI,CAAA,IAAA,EAAO,QAAQ,CAAA,yDAAA,CAA2D,CAC5H;YACD;QACF;QACA,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,KAAI;YAClD,OAAO,CAAC,IAAI,CAAC,CAAA,iCAAA,EAAoC,IAAI,CAAA,SAAA,CAAW,EAAE,KAAK,CAAC;AAC1E,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC;AACH;AAEA,SAAS,SAAS,CAAC,IAAa,EAAA;AAC9B,IAAA,QACE,OAAO,IAAI,KAAK,QAAQ;AACxB,QAAA,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;AACzB,QAAA,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;AAEzC;AAEA,SAAS,WAAW,CAClB,KAAqC,EAAA;IAErC,IAAI,OAAO,KAAK,KAAK,UAAU;AAAE,QAAA,OAAO,KAAK;AAC7C,IAAA,OAAO,CAAC,IAAI,KACV,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAI;QAClB,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,KAAK,IAAI;;;AAGlD,QAAA,IAAI,CAAC,SAAS,GAAG,CAAC;AAClB,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACxB,IAAA,CAAC,CAAC;AACN;;ACpFA;;AAEG;;ACFH;;AAEG;;"}
@@ -256,14 +256,14 @@ class JrComponentTestHost {
256
256
  parent = inject(Injector);
257
257
  component = signal(null, ...(ngDevMode ? [{ debugName: "component" }] : /* istanbul ignore next */ []));
258
258
  injector = signal(this.parent, ...(ngDevMode ? [{ debugName: "injector" }] : /* istanbul ignore next */ []));
259
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: JrComponentTestHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
260
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: JrComponentTestHost, isStandalone: true, selector: "jr-component-test-host", ngImport: i0, template: `
259
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrComponentTestHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
260
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: JrComponentTestHost, isStandalone: true, selector: "jr-component-test-host", ngImport: i0, template: `
261
261
  @if (component(); as type) {
262
262
  <ng-container *ngComponentOutlet="type; injector: injector()" />
263
263
  }
264
264
  `, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
265
265
  }
266
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: JrComponentTestHost, decorators: [{
266
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrComponentTestHost, decorators: [{
267
267
  type: Component,
268
268
  args: [{
269
269
  selector: 'jr-component-test-host',
@@ -420,8 +420,8 @@ class JrTestHost {
420
420
  validationFunctions = signal(undefined, ...(ngDevMode ? [{ debugName: "validationFunctions" }] : /* istanbul ignore next */ []));
421
421
  directives = signal(undefined, ...(ngDevMode ? [{ debugName: "directives" }] : /* istanbul ignore next */ []));
422
422
  record = () => { };
423
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: JrTestHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
424
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: JrTestHost, isStandalone: true, selector: "jr-test-host", ngImport: i0, template: `
423
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrTestHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
424
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.25", type: JrTestHost, isStandalone: true, selector: "jr-test-host", ngImport: i0, template: `
425
425
  <json-render
426
426
  [spec]="spec()"
427
427
  [registry]="registry()"
@@ -439,7 +439,7 @@ class JrTestHost {
439
439
  />
440
440
  `, isInline: true, dependencies: [{ kind: "component", type: JsonRenderer, selector: "json-render", inputs: ["spec", "registry", "loading", "fallback", "validate", "renderLimits", "catalog", "state", "store", "handlers", "onAction", "navigate", "validationFunctions", "functions", "directives"], outputs: ["stateChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
441
441
  }
442
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: JrTestHost, decorators: [{
442
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: JrTestHost, decorators: [{
443
443
  type: Component,
444
444
  args: [{
445
445
  selector: 'jr-test-host',