Skip to content
Draft
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
22 changes: 15 additions & 7 deletions skills/objectui/guides/page-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ When helping third-party apps, consume these packages; avoid duplicating core ru

### 3. Compose schema using proven node shape

Use a strict component schema shape similar to:
Use a strict component schema shape similar to this — a page whose host
published `userRole` and `metrics` (section 4, step 3, names the channel):

<!-- os:check -->
```json
Expand All @@ -40,11 +41,11 @@ Use a strict component schema shape similar to:
"id": "customer_summary",
"className": "col-span-12 lg:col-span-4",
"title": "Customer Summary",
"hidden": "${data.userRole !== 'admin'}",
"hidden": "${userRole !== 'admin'}",
"children": [
{
"type": "text",
"content": "Active users: ${data.metrics.activeUsers}"
"content": "Active users: ${metrics.activeUsers}"
}
]
}
Expand Down Expand Up @@ -98,7 +99,13 @@ Typical integration sequence:

1. Register default renderers/components.
2. Register plugin components needed by the page type.
3. Provide `dataSource` and contextual data through renderer provider.
3. Publish the roots the page's expressions read: wrap the tree in
`PredicateScopeProvider` (`@object-ui/react`) — every key of its `scope` is
a root (`userRole`, `metrics` above; `bind` reads the same bag). The renderer
itself adds `record` (the page's row) and `page` (page variables); nothing
publishes `data`, and `SchemaRendererProvider`'s `dataSource` is the adapter
the object-bound blocks fetch through, not a root. Provider fence:
[`guides/auth-permissions.md`](./auth-permissions.md).
4. Render schema via `SchemaRenderer`.

Keep custom component registrations namespaced to avoid collisions.
Expand Down Expand Up @@ -166,7 +173,8 @@ A key must clear **two independent gates** to reach the screen: the renderer has
to *read* it, and `SchemaRenderer` has to *evaluate* it. Both lists -- what is
evaluated, what is read raw, and what `props` / `properties` each do -- are in
[`rules/protocol.md`](../rules/protocol.md). Two consequences shape almost every
page:
page; both examples below read `metrics`, a root the host published (section 4,
step 3):

**A `statistic` carries its own text keys**, so both static values and
expressions work on the node (`statistic` declares `label` / `value` /
Expand All @@ -176,7 +184,7 @@ expressions work on the node (`statistic` declares `label` / `value` /
{
"type": "statistic",
"label": "Active Users",
"value": "${data.metrics.activeUsers}",
"value": "${metrics.activeUsers}",
"description": "+5% from last month",
"trend": "up"
}
Expand All @@ -190,7 +198,7 @@ is evaluated on every component type:
"type": "card",
"title": "Active Users",
"children": [
{ "type": "text", "content": "${data.metrics.activeUsers} active, +${data.metrics.growth}% this month" }
{ "type": "text", "content": "${metrics.activeUsers} active, +${metrics.growth}% this month" }
]
}
```
Expand Down
Loading