Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions apps/website/content/docs/render/api/define-angular-registry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,26 @@ import { defineAngularRegistry } from '@threadplane/render';

```typescript
function defineAngularRegistry(
componentMap: Record<string, AngularComponentRenderer>,
componentMap: Record<string, AngularComponentRenderer | RenderViewEntry>,
): AngularRegistry;
```

### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `componentMap` | `Record<string, AngularComponentRenderer>` | An object mapping type name strings to Angular component classes |
| `componentMap` | `Record<string, AngularComponentRenderer \| RenderViewEntry>` | An object mapping type name strings to Angular component classes, or to `{ component, fallback? }` objects |

`AngularComponentRenderer` is defined as `Type<unknown>` -- any Angular component class.
`AngularComponentRenderer` is defined as `Type<unknown>` -- any Angular component class. Each entry can be a bare component class or a `RenderViewEntry` object:

```typescript
interface RenderViewEntry {
component: AngularComponentRenderer;
fallback?: AngularComponentRenderer;
}
```

Use the object form to configure a custom per-entry fallback (see [Per-Component Fallbacks](#per-component-fallbacks) below). A bare component class is shorthand for `{ component }` paired with the library's default fallback.

### Returns

Expand Down Expand Up @@ -118,15 +127,33 @@ An entry that omits `fallback` -- including every bare-component entry like `Tex

## Internal Behavior

The function converts the input object to an internal `Map<string, AngularComponentRenderer>` for O(1) lookups:
The function normalizes each input entry into a `{ component, fallback }` pair and stores them in an internal `Map` for O(1) lookups. A bare component class is paired with `DefaultFallbackComponent`; an object entry keeps its own `fallback` or falls back to the default:

```typescript
function normalize(
entry: AngularComponentRenderer | RenderViewEntry,
): NormalizedEntry {
// Bare Type — register with the default fallback.
if (typeof entry === 'function') {
return { component: entry, fallback: DefaultFallbackComponent };
}
// Object form — preserve component; use configured fallback or default.
return {
component: entry.component,
fallback: entry.fallback ?? DefaultFallbackComponent,
};
}

function defineAngularRegistry(
componentMap: Record<string, AngularComponentRenderer>,
componentMap: Record<string, AngularComponentRenderer | RenderViewEntry>,
): AngularRegistry {
const map = new Map(Object.entries(componentMap));
const map = new Map<string, NormalizedEntry>();
for (const [name, entry] of Object.entries(componentMap)) {
map.set(name, normalize(entry));
}
return {
get: (name: string) => map.get(name),
get: (name: string) => map.get(name)?.component,
getFallback: (name: string) => map.get(name)?.fallback,
names: () => [...map.keys()],
};
}
Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/docs/render/api/provide-render.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface RenderConfig {
|----------|------|-------------|
| `registry` | `AngularRegistry` | Default component registry for all `<render-spec>` instances |
| `store` | `StateStore` | Default state store for all `<render-spec>` instances |
| `functions` | `Record<string, ComputedFunction>` | Default computed functions for `$fn` prop expressions |
| `functions` | `Record<string, ComputedFunction>` | Default computed functions for `$computed` prop expressions |
| `handlers` | `Record<string, Handler>` | Default event handlers for action dispatch |

All properties are optional. Only provide the defaults you need.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class MyComponent {
| `spec` | `Spec \| null` | `null` | The json-render spec to render. When `null`, nothing is rendered. |
| `registry` | `AngularRegistry \| undefined` | `undefined` | Component registry mapping element types to Angular components. |
| `store` | `StateStore \| undefined` | `undefined` | State store for reactive prop resolution. |
| `functions` | `Record<string, ComputedFunction> \| undefined` | `undefined` | Computed functions for `$fn` prop expressions. |
| `functions` | `Record<string, ComputedFunction> \| undefined` | `undefined` | Computed functions for `$computed` prop expressions. |
| `handlers` | `Record<string, (params: Record<string, unknown>) => unknown \| Promise<unknown>> \| undefined` | `undefined` | Event handlers invoked when components call `emit()`. |
| `loading` | `boolean` | `false` | Whether the spec is currently streaming. Passed to all rendered components as the `loading` input. |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The library resolves `Text` from your component registry, evaluates the `$state`

## How It Relates to @json-render/core

`@json-render/core` provides the spec format and the evaluation engine -- it resolves prop expressions (`$state`, `$item`, `$index`, `$bindState`, `$fn`), evaluates visibility conditions, and resolves bindings. It is framework-agnostic and has no Angular dependency.
`@json-render/core` provides the spec format and the evaluation engine -- it resolves prop expressions (`$state`, `$item`, `$index`, `$bindState`, `$computed`), evaluates visibility conditions, and resolves bindings. It is framework-agnostic and has no Angular dependency.

`@threadplane/render` is the Angular adapter layer. It provides:

Expand Down
12 changes: 5 additions & 7 deletions apps/website/content/docs/render/guides/specs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,20 @@ props: {
}
```

### $fn -- Computed Function
### $computed -- Computed Function

Calls a registered computed function with the given arguments:

```typescript
props: {
label: {
$fn: {
name: 'uppercase',
args: { text: { $state: '/name' } }
}
$computed: 'uppercase',
args: { text: { $state: '/name' } }
},
}
```

The `name` references a function you register in a `functions` map. Each function is a `ComputedFunction` from `@json-render/core` -- `(args: Record<string, unknown>) => unknown`. The `args` object is resolved first (so `{ $state: '/name' }` becomes the current value at `/name`), then passed to your function:
The `$computed` value names a function you register in a `functions` map. Each function is a `ComputedFunction` from `@json-render/core` -- `(args: Record<string, unknown>) => unknown`. The `args` object is resolved first (so `{ $state: '/name' }` becomes the current value at `/name`), then passed to your function:

```typescript
import type { ComputedFunction } from '@json-render/core';
Expand Down Expand Up @@ -154,7 +152,7 @@ provideRender({
});
```

With either wiring, the `$fn` expression above resolves `label` to the uppercased value of `/name`. The input takes priority over the `provideRender()` config when both are present.
With either wiring, the `$computed` expression above resolves `label` to the uppercased value of `/name`. The input takes priority over the `provideRender()` config when both are present.

## Children

Expand Down
Loading