From 3f455b8e711686836ed910584bf19fbc7ccd907c Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 14:56:33 +0000 Subject: [PATCH 1/2] docs(plugin-dashboard): teach the adapter as renderer context, not a schema key (objectui#8468) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Integration with Data Sources" example authored the live adapter returned by `createObjectStackAdapter` as a shorthand property inside the `dashboard` schema literal. Nothing reads it there: `ObjectMetricWidget` takes its adapter from `useContext(SchemaRendererContext)` (src/ObjectMetricWidget.tsx:159), falling back to an explicit `dataSource` prop. The slot is not merely redundant, it is a NAME COLLISION: a `dataSource` key on a schema node is the spec's element binding (`{ object, view?, filter?, sort?, limit? }`), a declarative reference resolved against the host — not an adapter instance. Repaired to the form already landed in `plugin-form`, `plugin-grid`, `plugin-gantt` and `plugin-view`: the literal is annotated with its own schema type (`DashboardComponentSchema`), and the prose says where the adapter actually goes — `SchemaRendererProvider`, above the tree. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH --- packages/plugin-dashboard/README.md | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/plugin-dashboard/README.md b/packages/plugin-dashboard/README.md index ee6c54a67a..09b920f814 100644 --- a/packages/plugin-dashboard/README.md +++ b/packages/plugin-dashboard/README.md @@ -271,17 +271,26 @@ it has no row in the spec's expression carriage map, so a `${…}` written in read live data is one of the `object-*` types above — they resolve the spec's per-element `dataSource` binding and query the object themselves. -```typescript +**The adapter is not a schema key.** A schema is a serialisable document; a live +adapter is an object with methods, so it cannot travel in one. An `object-*` +widget reads its adapter from React context — `useContext(SchemaRendererContext)` +at `src/ObjectMetricWidget.tsx:159`, with an explicit `dataSource` prop taking +precedence when the host renders the widget directly — and the host installs it +once, above the whole tree: + +```tsx +import { SchemaRendererProvider, SchemaRenderer } from '@object-ui/react'; import { createObjectStackAdapter } from '@object-ui/data-objectstack'; +import '@object-ui/plugin-dashboard'; +import type { DashboardComponentSchema } from '@object-ui/types'; const dataSource = createObjectStackAdapter({ baseUrl: 'https://api.example.com', token: 'your-auth-token' }); -const schema = { +const schema: DashboardComponentSchema = { type: 'dashboard', - dataSource, widgets: [ { type: 'metric-card', @@ -291,8 +300,22 @@ const schema = { } ] }; + +export const App = () => ( + + + +); ``` +> A `dataSource` key **does** mean something on a schema node, but it is not this: +> it is the spec's element **binding** (`PageComponentSchema.dataSource`) — a +> declarative descriptor such as `{ object: 'orders', view: 'my_view' }`, resolved +> against the host and mapped onto the widget's own keys by the `object-*` +> registry shells in `src/index.tsx`. It belongs on the widget that reads it, not +> on the dashboard node, and a live adapter written into that slot wires nothing +> up — it is a different kind of thing wearing the same name. + ## Dashboard-level filters A dashboard can declare top-level filters — a date range and any number of From 223100735ad992553eb7fafcf42e55d9d822914f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 15:44:00 +0000 Subject: [PATCH 2/2] docs(plugin-dashboard): split the provider wiring into its own fence (objectui#8468) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fence added for objectui#8468 carried the dashboard document AND the provider/JSX wiring. `readme-dashboard-examples-spec-valid.test.ts` extracts every fence matching both `/const\s+schema\b/` and `/type:\s*'dashboard'/` and evaluates it with `new Function`, which compiles neither a top-level `export` nor JSX — so the merge_group shard failed with `SyntaxError: Unexpected token 'export'` while the `pull_request` shards, skipped on a markdown-only diff, reported green. Split it in two rather than teaching `toEvaluable()` to swallow `export`/JSX: that harness's docblock states the deliberate remedy is naming an ambient, not widening the syntax it accepts, and an evaluator that skips what it cannot read is the false-green shape objectui#4846 exists to prevent. - fence 1 (`typescript`) — the document alone, still `const schema: DashboardComponentSchema = { type: 'dashboard', … }`, so the extractor still selects it and still validates it against the shipped schema. - fence 2 (`tsx`) — the adapter construction and the provider wiring, with its own imports and a `declare const schema` for the document above. It carries no `type: 'dashboard'`, so the extractor does not select it; the two fences split along that predicate's own semantic line. The extractor finds 6 blocks before and after, and selects the same documents. The closing note on the `dataSource` name collision is unchanged. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH --- packages/plugin-dashboard/README.md | 33 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/plugin-dashboard/README.md b/packages/plugin-dashboard/README.md index 09b920f814..fab0a7bc6f 100644 --- a/packages/plugin-dashboard/README.md +++ b/packages/plugin-dashboard/README.md @@ -275,19 +275,12 @@ per-element `dataSource` binding and query the object themselves. adapter is an object with methods, so it cannot travel in one. An `object-*` widget reads its adapter from React context — `useContext(SchemaRendererContext)` at `src/ObjectMetricWidget.tsx:159`, with an explicit `dataSource` prop taking -precedence when the host renders the widget directly — and the host installs it -once, above the whole tree: +precedence when the host renders the widget directly. -```tsx -import { SchemaRendererProvider, SchemaRenderer } from '@object-ui/react'; -import { createObjectStackAdapter } from '@object-ui/data-objectstack'; -import '@object-ui/plugin-dashboard'; -import type { DashboardComponentSchema } from '@object-ui/types'; +So the document stays plain data — every value in it survives `JSON.stringify`: -const dataSource = createObjectStackAdapter({ - baseUrl: 'https://api.example.com', - token: 'your-auth-token' -}); +```typescript +import type { DashboardComponentSchema } from '@object-ui/types'; const schema: DashboardComponentSchema = { type: 'dashboard', @@ -300,6 +293,24 @@ const schema: DashboardComponentSchema = { } ] }; +``` + +The adapter is installed once, above the whole tree, and every `object-*` widget +underneath reads it from context: + +```tsx +import { SchemaRendererProvider, SchemaRenderer } from '@object-ui/react'; +import { createObjectStackAdapter } from '@object-ui/data-objectstack'; +import '@object-ui/plugin-dashboard'; +import type { DashboardComponentSchema } from '@object-ui/types'; + +// The document from the block above. +declare const schema: DashboardComponentSchema; + +const dataSource = createObjectStackAdapter({ + baseUrl: 'https://api.example.com', + token: 'your-auth-token' +}); export const App = () => (