From 1086a1215262f137ebf80210f12dbf5aefb17852 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 01:08:32 +0000 Subject: [PATCH] docs(layout): name page:header as the canonical author key on the page-header docs The layout `page-header` docs page taught the legacy alias as the author face: its only live demo writes `"type": "page-header"`, and nothing on the page said that the contract's key is `page:header`. The layout guide's PageHeader section did the same in two snippets. Phase 1 of the 2026-08-09 maintainer ruling (direction (b), phased): a banner that tells the truth about the key's status now, so an AI author copying from the page copies the canonical spelling, ahead of the full-page rewrite that is serialized behind objectui#3789. Measured against the installed @objectstack/spec, with controls: - ComponentPropsMap has `page:header` (row -> PageHeaderProps), and neither `page-header` nor `layout:page-header`; control `page:tabs` = present. - PageComponentType includes `page:header`, not `page-header`; control `page:footer` = present. - PageHeaderProps.safeParse rejects `icon` by name (retiredKey) and `description` as an unrecognized key of "this `page:header`", with a nonsense key as the negative control. - The alias is STILL ACCEPTED, not tombstoned and not dropped: registerLayout() registers `page-header` (namespace `layout`, no skipFallback, so the bare key too), and it is what the page's demo renders. No schema, registry or renderer change; the demo and the page's measured Styling/Props stay on the alias's renderer, which is Phase 2's job. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01EuPCi56cnGyykygi3z9w4m --- content/docs/guide/layout.md | 12 ++++++++++++ content/docs/layout/page-header.mdx | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/content/docs/guide/layout.md b/content/docs/guide/layout.md index 304ca7aa61..89b4c3683b 100644 --- a/content/docs/guide/layout.md +++ b/content/docs/guide/layout.md @@ -228,6 +228,18 @@ Available values: The `PageHeader` provides consistent page headers with a title, an optional subtitle, an icon chip, and an action row. +> **The canonical author key is `page:header`; `page-header` is a legacy alias.** The +> snippets in this section are the `@object-ui/layout` component, which `registerLayout()` +> registers as `page-header` (plus its namespaced form `layout:page-header`) — that node +> still renders, so metadata already written this way is not stranded. The contract knows +> only `page:header`, though: that is the `PageComponentType` value and the +> `ComponentPropsMap` row binding `PageHeaderProps`, and it resolves to a different, +> record-aware renderer in `@object-ui/components`. Props written under the alias have no +> `ComponentPropsMap` row to dispatch, so nothing validates them — a misspelling there is +> neither rejected nor reported. Author metadata pages against `page:header` +> ([Slotted pages](/docs/guide/slotted-pages)); its props are not the ones below — see the +> [PageHeader reference](/docs/layout/page-header). + ### Usage ```json diff --git a/content/docs/layout/page-header.mdx b/content/docs/layout/page-header.mdx index 67bde65d79..7ab7240f63 100644 --- a/content/docs/layout/page-header.mdx +++ b/content/docs/layout/page-header.mdx @@ -3,6 +3,33 @@ title: "PageHeader" description: "Page header component with title, subtitle, and actions" --- +> **Canonical author key: `page:header`. This page's key, `page-header`, is a legacy alias +> — and it resolves to a different renderer.** +> +> Measured against the `@objectstack/spec` build this repo installs, `page:header` is the +> only spelling the contract knows: it is the `PageComponentType` value, and it is the +> `ComponentPropsMap` row that binds `PageHeaderProps` — whose own rejection messages name +> the surface `page:header`. Neither `page-header` nor `layout:page-header` appears in +> either place. +> +> The alias is **still accepted** — not retired, and not silently dropped. +> `registerLayout()` registers `page-header` (plus its namespaced form +> `layout:page-header`), so a node written that way renders today: it resolves to the +> `@object-ui/layout` component documented below, which is also what the demo on this page +> renders. What the alias does not carry is a contract. A node's props are validated by +> dispatching its `type` through `ComponentPropsMap`, `page-header` has no row there, and +> `PageComponentSchema.properties` is an open `z.record(z.string(), z.unknown())` bag — so +> a misspelled or retired key written under the alias is neither rejected nor reported. +> Under `page:header` the same key is refused by name. +> +> Author metadata pages against `page:header`. The canonical node is the record-aware +> renderer in `@object-ui/components`; [Slotted pages](/docs/guide/slotted-pages) shows it +> in place. Its props are **not** the props below — `icon`, `action` and `showBack` are this +> component's own, and `icon` is retired on the canonical node (Component Props, below). +> Everything on this page — Props, Styling, Examples, demo — is measured against this +> component, the alias's renderer; converting the page to the canonical node is tracked in +> objectui#3906. + The PageHeader component provides a consistent header for pages with title, subtitle, and action buttons. ## Basic Usage