关于 canvas-component-metadata
canvas-component-metadata 是用于 Drupal Canvas 组件元数据的开发技能,涵盖 component.yml、属性和插槽的建模规则。它还说明图像及实体引用等类型的模式,以及枚举值与实现变体的对应要求。
主要功能
- 01规定 component.yml 顶层结构
- 02说明属性类型与定义规则
- 03指导插槽建模
- 04规定枚举值与实现变体匹配
适用场景
- 01为组件编写或修改 component.yml
- 02设计 Canvas 可编辑属性与插槽
- 03排查属性验证及枚举配置问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ drupal-canvas/ skills --skill canvas-component-metadata安装后在 Claude Code 中输入/canvas-component-metadata确认已加载。
详细介绍
项目类型
应用此技能前,请检查 package.json 中是否包含名为
@drupal-canvas/headless 或以 @drupal-canvas/headless- 开头的依赖项。如果包含,
则这是一个 Canvas Headless 代码库——请先阅读
canvas-headless;其中的说明优先于下方针对
React 的指导。本技能中的 component.yml 架构在无头项目中完全相同。如果不包含此类依赖项,
则这是一个由 Canvas 渲染的 React 代码库:组件是 React(index.jsx/.tsx),本技能中的所有内容均适用。这是仅有的两种项目类型。
文件结构
每个 component.yml 都必须包含以下顶层键:
name: Component Name # Human-readable display name
machineName: component-name # Machine name in kebab-case
status: true # Whether the component is enabled
required: [] # Array of required prop names
props:
properties:
# ... prop definitions
slots: {} # Use an empty object when there are no slots
属性
要求
每个属性定义都必须包含用于 UI 标签的 title。必填属性必须提供 examples
数组,其他属性也建议提供。Drupal Canvas 只会使用第一个示例值。
如果某个属性列在 required 中,请勿在组件实现中为该属性添加回退值或默认值。
必填的 Canvas 属性应由元数据/编辑器输入提供,而不是使用静默的实现默认值。
props:
properties:
heading:
title: Heading
type: string
examples:
- Enter a heading...
// Correct: required prop has no fallback default
const Hero = ({ heading }) => <h1>{heading}</h1>;
// Wrong: required prop fallback masks missing required data
const Hero = ({ heading = 'Default heading' }) => <h1>{heading}</h1>;
属性 ID 必须是其标题对应的 camelCase 形式。
属性 ID(properties 下的键)必须是 title 值转换成的 camelCase 形式。
component.yml 中只包含面向用户、可由 Canvas 编辑的属性。
仅供实现使用的属性必须留在实现中,不得添加到元数据中。
切勿在 component.yml 中包含 className。 应将其视为供开发者使用的组合属性,而不是 Canvas 编辑器控件。
# Correct
props:
properties:
buttonText: # camelCase of "Button Text"
title: Button Text
type: string
backgroundColor: # camelCase of "Background Color"
title: Background Color
type: string
isVisible: # camelCase of "Is Visible"
title: Is Visible
type: boolean
# Wrong
props:
properties:
btn_text: # should be "buttonText" for title "Button Text"
title: Button Text
bgColor: # should be "backgroundColor" for title "Background Color"
title: Background Color
属性类型
文本
基本文本输入。以字符串值存储。
type: string
examples:
- Hello, world!
格式化文本
支持 HTML 格式的富文本内容,在块上下文中显示。
type: string
contentMediaType: text/html
x-formatting-context: block
examples:
- <p>This is <strong>formatted</strong> text with HTML.</p>
链接
用于链接到内部或外部资源的 URL 或 URI 引用。
type: string
format: uri-reference
examples:
- /about/contact
注意: 格式可以是 uri(仅接受绝对 URL),也可以是
uri-reference(接受绝对和相对 URL)。
重要:URL 属性必须使用合适的路径示例。 对于 uri-reference 属性,切勿使用 # 作为
示例值——这可能会导致推送时验证失败。请始终使用真实的类路径示例:
# Correct
examples:
- /resources
- /about/team
- https://example.com/page
# Wrong
examples:
- "#"
- ""
图像
对图像对象的引用,其中包含替代文本、尺寸和文件 URL 等元数据。任何表示单张图像的属性都使用此结构。请勿将单张图像建模为 imageUrl、imageAlt、imageWidth 或 imageHeight 等单独属性。
使用语义化的属性 ID,例如 image、backgroundImage、logoImage 或
cardImage,但值结构必须保持一致:type: object 加上 Canvas 图像架构引用。
type: object
$ref: json-schema-definitions://canvas.module/image
examples:
- src: >-
https://images.unsplash.com/photo-1484959014842-cd1d967a39cf?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80
alt: Woman playing the violin
width: 1770
height: 1180
将该属性建模为一个图像对象,而不是单独的 URL/替代文本字段:
# Correct
props:
properties:
image:
title: Image
type: object
$ref: json-schema-definitions://canvas.module/image
examples:
- src: https://example.com/photo.webp
alt: Product hero image
# Wrong
props:
properties:
imageUrl:
title: Image URL
type: string
format: uri-reference
imageAlt:
title: Image Alt
type: string
内容实体引用
对所选 Drupal 内容实体的结构化对象引用。当组件需要编辑器选择一个实体,并让 JSX 在一个 prop 上接收该实体的字段时,请使用此类型。
props:
properties:
featuredArticle:
title: Featured Article
type: object
$ref: json-schema-definitions://canvas.module/content-entity-reference
内容实体引用 prop 必须为可选项:不要将其列入 required。
不要编写 x-allowed-entity-type-id 或 x-allowed-bundle;Canvas 会从 dataDependencies.entityFields 中获取这些值。
不要为内容实体引用 prop 添加 examples。预览值由 dataDependencies.entityFields 解析。
添加 dataDependencies.entityFields.<propName>,其中包含一个或多个来自 .agents/drupal-canvas/content-entity-reference-expressions.json 的表达式。
如果 .agents/drupal-canvas/content-entity-reference-expressions.json 缺失、已过时或不包含所需的实体字段,请运行 npx canvas agents-context cer-expressions,仅从已配置的 Canvas 站点刷新内容实体引用表达式。
dataDependencies:
entityFields:
featuredArticle:
- ℹ︎␜entity:node:article␝title␞␟value
- ℹ︎␜entity:node:article␝path␞␟alias
同一个内容实体引用 prop 的所有表达式必须指向相同的实体类型和 bundle。不要仅根据表达式名称推断面向开发者的最终对象结构。本地组件元数据创建完成后,运行 npx canvas agents-context cer-preview <component>,检查 JSX 应使用的实际解析后 prop 结构。引用表达式可以创建嵌套对象,并包含 __type 等元数据键。
视频
对视频对象的引用,包含尺寸和文件 URL 等元数据。必须存在的只有文件 URL;其他所有元数据始终为可选项。
type: object
$ref: json-schema-definitions://canvas.module/video
examples:
- src: https://media.istockphoto.com/id/1340051874/video/aerial-top-down-view-of-a-container-cargo-ship.mp4?s=mp4-640x640-is&k=20&c=5qPpYI7TOJiOYzKq9V2myBvUno6Fq2XM3ITPGFE8Cd8=
poster: https://example.com/600x400.png
布尔值
真或假值。
type: boolean
examples:
- false
整数
没有小数位的整数值。
type: integer
examples:
- 42
数字
可包含小数位的数值。
type: number
examples:
- 3.14
列表:文本
用户可从中选择的预定义文本选项列表。
type: string
enum:
- option1
- option2
- option3
meta:enum:
option1: Option 1
option2: Option 2
option3: Option 3
examples:
- option1
列表:整数
用户可从中选择的预定义整数选项列表。
type: integer
enum:
- 1
- 2
- 3
meta:enum:
1: Option 1
2: Option 2
3: Option 3
examples:
- 1
枚举
枚举值必须使用小写、便于机器处理的标识符。使用 meta:enum 为 UI 提供易读的显示标签。
注意: 枚举值不能包含句点。
# Correct
enum:
- left_aligned
- center_aligned
meta:enum:
left_aligned: Left aligned
center_aligned: Center aligned
examples:
- left_aligned
# Wrong
enum:
- Left aligned
- Center aligned
examples 的值必须是枚举值,而不是显示标签。
枚举值必须与实现中的变体键匹配
当实现通过变体映射将枚举 prop 映射到样式时——无论使用 class-variance-authority(CVA)还是普通变体对象——变体键都必须与 component.yml 中定义的枚举值完全匹配。
// component.yml defines: enum: [left_aligned, center_aligned]
// CVA variants must match:
const variants = cva('base-classes', {
variants: {
layout: {
left_aligned: 'text-left', // matches enum value
center_aligned: 'text-center', // matches enum value
},
},
});
插槽
插槽允许在组件中嵌入其他组件。实现对插槽的处理方式取决于框架:
- React: 每个插槽都会作为与插槽键同名的 prop 接收。
- Vue 和 Astro(无头项目): 每个插槽都会作为具名插槽渲染,例如
<slot name="slotKey" />。
本节是插槽模式的唯一事实来源。其他技能应遵循这些规则,而不是重新定义插槽模式的细节。
创建插槽前,请先与用户确认,除非用例明显属于组合式(例如,丰富的嵌套内容或可重复嵌入的组件)。对于简单的类文本值,优先使用 prop。
重要: 默认不要将 Canvas 插槽映射到 children prop。如果插槽键是 content,则在 JSX 中将其作为 content 使用。
技术上可以使用名为 children 的插槽键,但不建议这样做,因为插槽名称通常会显示为面向用户的 Canvas 标签。优先使用 content、media 或 actions 等明确的插槽键。
slots 必须是以插槽名称(如 content、sidebar 等)为键的对象映射。组件没有插槽时使用空对象。
slots:
content:
title: Content
buttons:
title: Buttons
在 React 组件中,插槽会解构为具名 prop 并直接渲染:
const Section = ({ width, content }) => {
return <div className={sectionVariants({ width })}>{content}</div>;
};
// Wrong when the slot key is `content`: this does not consume the named slot.
const Section = ({ children }) => {
return <div>{children}</div>;
};
组件没有插槽时,使用 slots: {}:
slots: {}
不要使用插槽对象数组:
# Wrong
slots:
- name: content
title: Content