发现于 #3787 的实现(PR:claude/issue-3786-3787-pageheader-docs-demo),不在该 PR 处理 —— 那一单是文档/示例面,这一条要改注册元数据(声明面),是另一类动作。
现象
PageHeader 有意把 schema.children 渲染进右侧槽,PageHeader.tsx:179-190 的注释把这件事写得很明确:
// Render schema-declared children into the action slot. `SchemaRenderer`
// strips `children` from the React tree (treats them as metadata), so
// we re-introduce them here for components like `record:quick_actions`
// nested under `page:header.children`.
content/docs/layout/page-header.mdx 也把它写成公开契约的一部分:「Precedence for the right-aligned slot is action → React children → actions → schema children」。#3787 落地后,该文档页唯一的 live demo 就是这个写法(page-header 节点 + 两个 button children),实测能正常渲染。
但 packages/layout/src/index.ts:50-58 的注册没有 isContainer: true。而 packages/sdui-parser/src/validate.ts:88-96 拿这个 flag 判定 containment:
if (node.children?.length && !comp.isContainer) {
diagnostics.push({
severity: 'warning',
code: 'not-a-container',
message: `${node.type} does not accept children`,
tag: node.type,
});
}
于是同一份 JSON:组件正常渲染(isContainer 在渲染路径上根本没有消费者 —— 实测它只喂 sdui-parser 这条诊断、Studio 调色板元数据 page.tsx:464 / react-page.tsx:66、以及 codegen 的文档表格),但仓库自己的校验器说它不接受 children。
为什么值得记一笔
inputs / isContainer 是声明面,#3226 已经为同一个组件定过调子:声明面是设计器提供的字段、也是 framework check:react-declaration-parity 的比对对象,声明错了等于告诉作者(尤其 AI 作者)一件不成立的事。这里是反向的同一个病:组件支持、文档承诺、demo 演示的写法,声明面否认它,校验器据此报警。作者照文档写 → 拿到一条 warning;信了 warning 去掉 children → 右槽空掉。
需要先定的一点(所以本条只记录)
@objectstack/spec/ui 的 PageHeaderProps 声明的是 title / subtitle / icon / breadcrumb / actions / aria,没有 children。children 是 objectui 自己 JSON 协议里每个节点的基础属性,不是 PageHeaderProps 的键。所以「补 isContainer: true」到底是
- A. 承认 children 是 page-header 的合法槽位 —— 补 flag,warning 消失,与组件行为和文档一致;但等于在 spec 之外确认了一个 spec 没声明的作者面。
- B. 认为 children 才是错的 —— 保留 flag 缺失,改文档与 demo 改用 spec 声明的
actions,并把 PageHeader.tsx 里读 schema.children 的分支按 ADR-0049 enforce-or-remove 处理。代价是 record:quick_actions 嵌在 page:header.children 下这个已有用法(注释里点名的那个)会被判为违规,需要先量清有多少 metadata 这样写。
两个方向对「作者能写什么」给出相反答案,属于契约决定,不该由实现者顺手选。
参考位置
关联:#3787(发现于此)、#3226(同一组件声明面的前情)
发现于 #3787 的实现(PR:
claude/issue-3786-3787-pageheader-docs-demo),不在该 PR 处理 —— 那一单是文档/示例面,这一条要改注册元数据(声明面),是另一类动作。现象
PageHeader有意把schema.children渲染进右侧槽,PageHeader.tsx:179-190的注释把这件事写得很明确:content/docs/layout/page-header.mdx也把它写成公开契约的一部分:「Precedence for the right-aligned slot isaction→ Reactchildren→actions→ schema children」。#3787 落地后,该文档页唯一的 live demo 就是这个写法(page-header节点 + 两个 button children),实测能正常渲染。但
packages/layout/src/index.ts:50-58的注册没有isContainer: true。而packages/sdui-parser/src/validate.ts:88-96拿这个 flag 判定 containment:于是同一份 JSON:组件正常渲染(
isContainer在渲染路径上根本没有消费者 —— 实测它只喂 sdui-parser 这条诊断、Studio 调色板元数据page.tsx:464/react-page.tsx:66、以及 codegen 的文档表格),但仓库自己的校验器说它不接受 children。为什么值得记一笔
inputs/isContainer是声明面,#3226 已经为同一个组件定过调子:声明面是设计器提供的字段、也是 frameworkcheck:react-declaration-parity的比对对象,声明错了等于告诉作者(尤其 AI 作者)一件不成立的事。这里是反向的同一个病:组件支持、文档承诺、demo 演示的写法,声明面否认它,校验器据此报警。作者照文档写 → 拿到一条 warning;信了 warning 去掉 children → 右槽空掉。需要先定的一点(所以本条只记录)
@objectstack/spec/ui的PageHeaderProps声明的是title / subtitle / icon / breadcrumb / actions / aria,没有children。children是 objectui 自己 JSON 协议里每个节点的基础属性,不是PageHeaderProps的键。所以「补isContainer: true」到底是actions,并把PageHeader.tsx里读schema.children的分支按 ADR-0049 enforce-or-remove 处理。代价是record:quick_actions嵌在page:header.children下这个已有用法(注释里点名的那个)会被判为违规,需要先量清有多少 metadata 这样写。两个方向对「作者能写什么」给出相反答案,属于契约决定,不该由实现者顺手选。
参考位置
packages/layout/src/index.ts:50-58(注册,缺isContainer)packages/layout/src/PageHeader.tsx:179-190、:207(有意读schema.children)packages/sdui-parser/src/validate.ts:88-96(not-a-container诊断)content/docs/layout/page-header.mdx(右槽优先级的文字承诺)examples/schema-catalog/src/schemas/layout-page-header/pageheader-with-actions.json(docs/examples: PageHeader 文档页的唯一 live demo(layout-page-header/pageheader-with-actions)手搓 div,完全不用page-header#3787 落地后的 demo)关联:#3787(发现于此)、#3226(同一组件声明面的前情)