ngx-json-render 0.8.2 → 0.9.0

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
@@ -273,6 +273,40 @@ export class GeneratePage {
273
273
  }
274
274
  ```
275
275
 
276
+ ### Placeholders while props stream
277
+
278
+ An element can arrive before its props do: a Card with no `title` yet, a Text
279
+ with no `content`. By default the component mounts anyway and renders what it
280
+ has. Pass the `catalog` and the renderer waits instead: while `loading` is
281
+ true, an element whose props do not pass its component's schema shows its
282
+ registry entry's `fallback`, or nothing, and the component mounts once they
283
+ do.
284
+
285
+ ```ts
286
+ export const { registry } = defineRegistry(catalog, {
287
+ components: {
288
+ Card: { component: CardComponent, fallback: CardSkeleton },
289
+ Text: TextComponent, // nothing on screen until `content` arrives
290
+ },
291
+ });
292
+ ```
293
+
294
+ ```html
295
+ <json-render [spec]="ui.spec()" [registry]="registry" [catalog]="catalog" [loading]="ui.isStreaming()" />
296
+ ```
297
+
298
+ - The fallback gets the same render context as the component: it can read
299
+ the props that have arrived, and a `<jr-children />` in it lays out the
300
+ children that have.
301
+ - Props are checked as the spec writes them. `{ "$state": "/title" }` counts
302
+ as arrived, whatever it resolves to.
303
+ - Once an element's component has mounted it stays, even if a later patch
304
+ takes a prop away again.
305
+ - When `loading` turns false every element mounts, valid or not; reporting
306
+ what is wrong with the finished spec is `validate`'s job.
307
+ - Without a `catalog`, or for a type the catalog has no props schema for,
308
+ nothing is held back.
309
+
276
310
  ### The server side
277
311
 
278
312
  `injectUIStream` POSTs `{ prompt, context, currentSpec }` to your endpoint and expects the response body to be SpecStream JSONL — one RFC 6902 patch per line. Any server that can stream text works; with the [AI SDK](https://ai-sdk.dev) it's a few lines — `catalog.prompt()` teaches the model your component vocabulary and the patch protocol:
@@ -744,6 +778,37 @@ value it derives updates when that state does.
744
778
  `projects/ngx-json-render/src/lib/directives.spec.ts` renders every one of
745
779
  them through the renderer, which is what keeps this paragraph honest.
746
780
 
781
+ ### Switching language
782
+
783
+ Where a spec's text comes from decides how it follows a language switch.
784
+
785
+ **Keys, translated on the client.** A spec that says
786
+ `{ "$t": "greeting", "params": { "name": { "$state": "/name" } } }` instead of
787
+ the words themselves switches in place. Derive `directives` from your locale
788
+ signal, and every prop re-resolves when it changes, with no new spec and
789
+ nothing remounted:
790
+
791
+ ```ts
792
+ readonly locale = signal('en');
793
+ readonly directives = computed(() => [
794
+ ...standardDirectives,
795
+ createI18nDirective({ locale: this.locale(), messages }),
796
+ ]);
797
+ ```
798
+
799
+ `$format` takes a `locale` the same way, for numbers, currency and dates.
800
+
801
+ **Words, written by the model.** Most generated UIs are this kind: the model
802
+ writes "Save" or "Сохранить" straight into the props. Tell it the language
803
+ through `context` (`ui.send(prompt, { context: { locale } })`) and say what to
804
+ do with it in your server's prompt. Text already on screen stays in the
805
+ language it was written in; switching means asking again, and
806
+ `previousSpec` keeps the layout while the model rewrites the words.
807
+
808
+ Text inside your catalog components is your app's own i18n, as it would be
809
+ anywhere else. The confirm dialog's two default words are `JR_CONFIRM_LABELS`
810
+ (see [Confirmation dialogs](#confirmation-dialogs)).
811
+
747
812
  ## State
748
813
 
749
814
  Each `<json-render>` owns a state store (JSON Pointer addressed). Seeding order: `store` input (controlled) → `state` input → `spec.state`.
@@ -982,7 +1047,7 @@ Everything from `@json-render/core` (types, `createStateStore`, `nestedToFlat`,
982
1047
  | `fallback` | `Type<unknown>` | Component for unknown types |
983
1048
  | `validate` | `'off' \| 'warn' \| 'strict'` | Check the settled spec's structure (default `'off'`) |
984
1049
  | `renderLimits` | `RenderLimits` | Cap elements, depth and repeat expansion (default none) |
985
- | `catalog` | `Catalog` | Also check types and props against the catalog |
1050
+ | `catalog` | `Catalog` | Check types and props; hold back half-streamed props |
986
1051
  | `state` | `StateModel` | Initial state (uncontrolled; defaults to `spec.state`) |
987
1052
  | `store` | `StateStore` | External store (controlled mode) |
988
1053
  | `handlers` | `Record<string, ActionHandler>` | Action handlers |