mcpField
C
canvas-component-metadata

canvas-component-metadata

github.com/drupal-canvas开发3246 次安装6 周前更新
代码仓库

关于 canvas-component-metadata

canvas-component-metadata 是用于 Drupal Canvas 组件元数据的开发技能,涵盖 component.yml、属性和插槽的建模规则。它还说明图像及实体引用等类型的模式,以及枚举值与实现变体的对应要求。

主要功能

  1. 01规定 component.yml 顶层结构
  2. 02说明属性类型与定义规则
  3. 03指导插槽建模
  4. 04规定枚举值与实现变体匹配

适用场景

  1. 01为组件编写或修改 component.yml
  2. 02设计 Canvas 可编辑属性与插槽
  3. 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

评论

支持 Markdown