From 62c8b498a02ccbf975e3f686106757551977aa34 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 02:17:33 +0000 Subject: [PATCH 1/2] docs(blocks): correct block-schema.mdx to the declared vocabulary (#4895) Carries the recorded maintainer ruling on #4895 (Option B: docs-truth fix, family re-scoped as type-level). - Delete the phantom `type: 'slot'` node from the Complete Example template. Nothing registers `slot`, so a reader who copied it got OBJUI-001. - Teach the declared `slotContent` path instead, and state plainly that it is declared-but-not-yet-consumed: nothing reads `slots` / `slotContent` / `template` at runtime. - Frame `BlockSchema` as a definition and drop the component-schema framing for `block-library` / `block-editor` / `block-instance`. - Disambiguate from the slot system that IS wired end to end (slotted record pages), which is an unrelated vocabulary. - Drop the now-stale `slot` entry from DOC_TYPE_EXEMPTIONS in scripts/check-doc-component-types.mjs, and re-point the three terse family reasons at the ruling's framing. Option A (build renderers) is rejected on zero pull; Option C (retire the family) is deferred. Neither is implemented here. --- content/docs/blocks/block-schema.mdx | 91 +++++++++++++++++++++------ scripts/check-doc-component-types.mjs | 25 +++++--- 2 files changed, 88 insertions(+), 28 deletions(-) diff --git a/content/docs/blocks/block-schema.mdx b/content/docs/blocks/block-schema.mdx index bd874b6880..1d0fcb2050 100644 --- a/content/docs/blocks/block-schema.mdx +++ b/content/docs/blocks/block-schema.mdx @@ -1,26 +1,51 @@ --- title: "Block Schema (BlockSchema)" -description: "Reusable component blocks with variables, slots, and marketplace support" +description: "Type-level declarations for reusable component blocks: variables, slots, templates and marketplace metadata. No renderer consumes this family." --- import { SchemaExample } from '@/app/components/ComponentDemo'; # Block Schema -The `BlockSchema` defines reusable component blocks that can be configured with variables, support content injection through slots, and shared via a marketplace. +`BlockSchema` is a **definition**, not a rendered node. It declares the shape of a +reusable component block: the variables it accepts, the slots it advertises, the +template it would expand to, and the metadata a marketplace listing would carry. + + +Every schema on this page is a **declaration** in `@object-ui/types`, mirrored by a Zod +validator in `@object-ui/types/zod`. Those declarations and their validators are the +whole implementation: + +- **No component is registered** for `block`, `block-library`, `block-editor` or + `block-instance`, and none of them appears in `AnySchema`, the runtime node union in + `packages/types/src/index.ts`. They are discriminants of the interfaces below, **not + renderable node types**. Putting one into a `children` array gives you the renderer's + `OBJUI-001` "Unknown component type" panel. +- **Nothing reads `slots`, `slotContent` or `template` at runtime.** There is no block + expander, no block library UI and no block editor in this repository. The keys are + declared and validated, and that is all. + +So use these types to **describe** a block (author tooling, a marketplace payload, a +validation step) and do not expect one to render. Looking for slots that work today? +That is an unrelated vocabulary: record pages support `kind: "slotted"` with a `slots` +map, wired end to end. See [Slotted Pages](/docs/guide/slotted-pages). + ## Overview -BlockSchema enables: -- **Reusable components** - Create once, use everywhere -- **Variable system** - Typed props for customization -- **Slot system** - Content injection points -- **Block templates** - Predefined component trees -- **Marketplace support** - Share and discover blocks -- **Version control** - Track block versions +`BlockSchema` declares: +- **Variables** - typed, defaultable parameters a block accepts +- **Slots** - named content-injection points a block advertises +- **Template** - the component tree a block would expand to +- **Marketplace metadata** - author, version, license, preview and rating fields +- **Version** - a `version` string carried on the block's metadata ## Interactive Examples +These demos are ordinary **registered** components (`card`, `flex`, `stack`, `text`, +`icon`, `button`, `badge`) hand-assembled to show what a block *would* look like once +expanded. None of them goes through `BlockSchema`: there is nothing that expands one. + ### Feature Card Block @@ -133,6 +158,32 @@ interface BlockSlot { } ``` +#### Filling a slot: `slotContent` + +A block **declares** its slots in `slots[]`; a caller **fills** them through +`slotContent`, a map keyed by slot name whose values are `SchemaNode | SchemaNode[]`. +The key is declared on both `BlockSchema` and `BlockInstanceSchema` +(`packages/types/src/blocks.ts`): + +```plaintext +// The block declares a slot named 'content'... +slots: [ + { name: 'content', label: 'Content Area' } +], + +// ...and a caller fills it by name. +slotContent: { + content: [ + { type: 'text', value: 'Injected into the "content" slot' } + ] +} +``` + +**There is no `slot` node type.** Slot content is never addressed by placing a +`{ type: 'slot' }` placeholder inside `template`: nothing registers `slot`, so such a +node renders as `OBJUI-001`. `slotContent` is the declared path, and like the rest of +this family it is **declared but not yet consumed** - no renderer reads it today. + ## Complete Example ```plaintext @@ -250,10 +301,6 @@ const cardBlock: BlockSchema = { value: '${description}', className: 'card-description' }, - { - type: 'slot', - name: 'content' - }, { type: 'button', label: '${buttonText}', @@ -274,7 +321,9 @@ const cardBlock: BlockSchema = { ### Block Instance -Use `BlockInstanceSchema` to instantiate a block: +`BlockInstanceSchema` declares the shape of a **reference to a block**: which block, what +variable values, what slot content. It is a definition, not a component - nothing +resolves `blockId` or expands the block it names. ```plaintext import type { BlockInstanceSchema } from '@object-ui/types'; @@ -311,7 +360,10 @@ const instance: BlockInstanceSchema = { ## Block Library -Use `BlockLibrarySchema` to browse available blocks: +`BlockLibrarySchema` declares the shape of a **block-library payload**: the query that +selected it and the listings it returned. It is a data shape, not a browser component - +nothing renders a library, and `onInstall` / `onPreview` name handlers that no dispatcher +looks up. ```plaintext import type { BlockLibrarySchema } from '@object-ui/types'; @@ -347,7 +399,9 @@ const library: BlockLibrarySchema = { ## Block Editor -Use `BlockEditorSchema` to create/edit blocks: +`BlockEditorSchema` declares the shape of a **block-editor configuration**: which block is +open and which panels a host would show. It is a configuration shape, not an editor +component - no block editor exists to consume it. ```plaintext import type { BlockEditorSchema } from '@object-ui/types'; @@ -472,6 +526,7 @@ if (result.success) { ## Related -- [Component Registry](/docs/guide/component-registry) - Registering components -- [Schema Rendering](/docs/guide/schema-rendering) - Rendering blocks +- [Slotted Pages](/docs/guide/slotted-pages) - the slot system that **is** wired end to end +- [Component Registry](/docs/guide/component-registry) - what registering a renderable type takes +- [Schema Rendering](/docs/guide/schema-rendering) - how registered node types are rendered - [Plugins](/docs/guide/plugins) - Extending ObjectUI diff --git a/scripts/check-doc-component-types.mjs b/scripts/check-doc-component-types.mjs index 7755916543..b64e095381 100644 --- a/scripts/check-doc-component-types.mjs +++ b/scripts/check-doc-component-types.mjs @@ -271,18 +271,23 @@ const DOC_TYPE_EXEMPTIONS = { 'BlockSchema discriminant — `packages/types/src/blocks.ts` declares `type: \'block\'`, and ' + '`packages/types/src/zod/blocks.zod.ts` validates it. A block definition is not a rendered node.', 'block-instance': - 'BlockInstanceSchema discriminant — packages/types/src/blocks.ts:357, zod/blocks.zod.ts:130.', + 'BlockInstanceSchema discriminant — packages/types/src/blocks.ts:357, zod/blocks.zod.ts:130. A ' + + 'reference to a block is a definition, not a rendered node: it is absent from `AnySchema` ' + + '(types/src/index.ts) and nothing resolves its `blockId`.', 'block-library': - 'BlockLibrarySchema discriminant — packages/types/src/blocks.ts:263, zod/blocks.zod.ts:100.', + 'BlockLibrarySchema discriminant — packages/types/src/blocks.ts:263, zod/blocks.zod.ts:100. The ' + + 'shape of a block-library PAYLOAD, not a browser component: absent from `AnySchema`, and no ' + + 'renderer reads it.', 'block-editor': - 'BlockEditorSchema discriminant — packages/types/src/blocks.ts:315, zod/blocks.zod.ts:116.', - slot: - 'Block slot placeholder inside `BlockSchema.template`, which IS a `SchemaNode` — so unlike its ' + - 'siblings above this one sits on the render path and nothing registers `slot`. Filed as ' + - 'objectui#4895: the correct spelling is not one thing (register a slot node, or route the ' + - 'snippet through the declared `slotContent` key), and objectui#4823 does not pre-decide it. ' + - 'DELETE this entry when #4895 lands — the gate reports a stale exemption, so it cannot be ' + - 'forgotten.', + 'BlockEditorSchema discriminant — packages/types/src/blocks.ts:315, zod/blocks.zod.ts:116. The ' + + 'shape of an editor CONFIGURATION, not an editor component: absent from `AnySchema`, and no ' + + 'block editor exists to consume it.', + // `slot` was here, exempted pending objectui#4895. That card ruled (maintainer, + // 2026-08-19, recorded on the issue): Option B, docs-truth fix — the family stays + // type-level, the phantom `type: 'slot'` node is DELETED from the page, and the + // page teaches the declared `slotContent` key instead. `slot` is now spelled + // nowhere in blocks/block-schema.mdx, so an exemption for it would itself fail as + // `stale-exemption`. Nothing to exempt; the entry is gone rather than re-pointed. string: 'BlockVariable.type — a variable declaration\'s data type, next to `defaultValue` / `required`.', }, From ca35295a991679924f94b88a1c6dce970447ea7e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 02:22:03 +0000 Subject: [PATCH 2/2] chore(changeset): declare no release for the #4895 docs-truth fix Empty frontmatter: docs and a gate ledger only, no released package `src/` is touched. Declared explicitly rather than left undeclared. --- .changeset/block-schema-docs-truth-4895.md | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .changeset/block-schema-docs-truth-4895.md diff --git a/.changeset/block-schema-docs-truth-4895.md b/.changeset/block-schema-docs-truth-4895.md new file mode 100644 index 0000000000..3019d9ed00 --- /dev/null +++ b/.changeset/block-schema-docs-truth-4895.md @@ -0,0 +1,46 @@ +--- +--- + +Docs and a gate ledger only — this publishes nothing, declared explicitly with an empty +frontmatter rather than left undeclared. No package `src/` is touched: the two files +changed are `content/docs/blocks/block-schema.mdx` and +`scripts/check-doc-component-types.mjs`. + +Corrects `content/docs/blocks/block-schema.mdx` to the vocabulary the repository actually +declares, per the maintainer ruling recorded on objectui#4895 (Option B: docs-truth fix, +the block family re-scoped as type-level). + +The page taught a `{ type: 'slot', name: 'content' }` node inside +`BlockSchema.template`. `template` is typed `SchemaNode | SchemaNode[]`, so that snippet +sat on the render path — and `slot` is registered nowhere. Measured against the +`check-doc-component-types.mjs` derivation of the registered universe (659 keys), the only +keys matching `/block|slot/` are `blockquote` and `ui:blockquote`. A reader who copied the +snippet got the renderer's `OBJUI-001` "Unknown component type" panel. That node is +deleted, and the page now teaches `slotContent`, the key `BlockSchema` and +`BlockInstanceSchema` actually declare. + +**`slotContent` is documented as declared-but-not-yet-consumed, not as the working path**, +because that is what it measures as. Outside `packages/types` — the interface, its Zod +mirror, and that package's own parse test — nothing in the repository reads `slotContent`, +`slots` or `template`. Rewriting one phantom into a second phantom is the failure this card +exists to close, so the page states the status plainly instead of implying a runtime that +does not exist. For the same reason the component-schema framing is dropped from +`block-library` / `block-editor` / `block-instance`: none of them appears in `AnySchema`, +the runtime node union in `packages/types/src/index.ts`. + +Two further measurements are written into the page because they are what a confused reader +needs. The four `` demos it embeds are ordinary registered component trees +(`card`, `flex`, `stack`, `text`, `icon`, `button`, `badge`) — none carries `type: 'block'`, +`slots` or `slotContent`, so nothing on the page was ever exercising the block vocabulary. +And the slot system that *is* wired end to end is a different family entirely: slotted +record pages (`kind: "slotted"`, `page.slots`), consumed by `usePageAssignment`, +`PageBlockCanvas` and `PageBlockInspector`. The page now links there rather than leaving the +two `slots` spellings to be conflated. + +The `slot` entry in `DOC_TYPE_EXEMPTIONS` pointed at this card and is dropped, as the ruling +requires. With the phantom node gone the entry would itself fail as `stale-exemption`, so it +is deleted rather than re-pointed; the three terse family reasons are re-pointed at the +ruling's framing in the same pass. + +Option A (build renderers for the family) is rejected on zero pull and Option C (retire the +family) is deferred; neither is implemented here.