mcpField
C
canvas-component-composability

canvas-component-composability

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

关于 canvas-component-composability

面向 Drupal Canvas 组件设计的组合性技能,帮助开发者规划 Props、插槽、变体和组件边界。强调可复用的布局与子组件组合,避免把重复内容压成复杂属性。

主要功能

  1. 01规划 Props 与插槽
  2. 02用变体表达预设样式
  3. 03采用父插槽与子组件模式
  4. 04评估组件拆分或合并
  5. 05遵循 Canvas 属性建模约束

适用场景

  1. 01设计可重复使用的卡片网格
  2. 02为 Canvas 编辑器规划组件控制项
  3. 03重构过多属性的组件
  4. 04将重复内容拆分为子组件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/drupal-canvas/skills --skill canvas-component-composability

安装后在 Claude Code 中输入/canvas-component-composability确认已加载。

附带文件references/repeatable-content.md

详细介绍

优先使用小型、专注的组件,而不是带有许多属性的单体组件。当组件开始积累许多互不相关的属性时,应将其拆分为更小、可组合的部分。

对于可重复使用的卡片/列表/网格 UI,默认使用两个 Canvas 组件:一个带有可放置重复子项的插槽的父布局组件,以及一个用于单个项的子组件。不要将重复项扁平化为编号属性组,例如 car1Name、car2Name、feature1Title 或 card3Image。

归属范围

本技能负责以下可复用建模规则:

  • 属性与插槽的取舍
  • 变体与细粒度属性的取舍
  • 可重复内容模式
  • 粒度检查(拆分、合并、提取插槽)

规范的复用优先策略请遵循 canvas-component-definition。有关 component.yml 的确切语法和插槽架构,请遵循 canvas-component-metadata。

复用现有组件

当任务点名现有组件或明显暗示要进行组合时,创建新组件前应先按照 canvas-component-definition 进行复用检查。本技能重点讲解边界明确后组件如何组合。

参考索引

仅在需要时加载参考资料:

  • 可重复列表/网格以及从数组转换为插槽: references/repeatable-content.md
  • 空 flex/grid 容器中插槽的交互性: references/repeatable-content.md(“Slot container minimum size”部分)

属性与插槽

插槽是实现可组合性的主要机制。不要通过属性传递复杂数据,而应使用插槽,让父组件接受子组件。这与 Canvas 用户通过将组件放入其他组件来构建页面的方式一致。在编写 component.yml 之前,应使用以下设计时准则。

何时使用插槽或属性
插槽适用场景属性适用场景
子组件数量可变单个必需值(文本、URL)
用户应当能够组合的内容配置选项(尺寸、颜色)
复杂的嵌套结构简单数据(字符串、布尔值)
在不同实例间变化的内容在不同实例间保持一致的内容

单张图片应作为一个属性,而不是插槽,也不要拆成多个 URL/替代文本属性。如果组件需要一张图片,请使用语义化的图片属性,例如 image 或 backgroundImage,并引用 Canvas 图片架构。

对于可重复的卡片/项,父组件通常负责标题、介绍文本、对齐方式或列数等布局属性,而每个子组件负责标题、图片、价格、标签、CTA 或元数据等项内容属性。

可重复的富内容项应采用“父组件插槽 + 子组件”模式,而不是对象数组属性。请参阅 references/repeatable-content.md。

对内容块应用这些准则时,预设和简单文案保留在属性中;卡片网格、标签页面板、页脚列或可替换区域则应放在插槽或具有各自插槽的嵌套子组件中。不要将大型组合区域编码为字符串属性或 JSON 块。

变体与细粒度属性

每个组件只采用一种主要建模风格。有时也可以采用混合方式:一个 variant 加上一两个正交开关。

变体是默认选择:

  • 主要的 variant 枚举用于选择命名预设,其值代表一组样式和结构规则。
  • 当设计包含命名预设,或许多任意组合都不合理时,使用主要的 variant 枚举。
  • 将 variant 用作主要预设字段的属性 ID,不要使用 appearance 或 layoutVariant 等同义名称。
  • 仅当 size 或 density 等维度具有独立意义时,才添加正交枚举。
  • 变体通常能减少无效组合、简化 Canvas 表单,并更便于与设计系统或 Figma 变体保持一致。
  • 将枚举值映射到 CVA 或等效的实现分支和主题令牌。

适合使用细粒度属性的情况:

  • 用户明确希望为每个维度提供独立控件
  • 这些维度的多种组合都各自有效
  • 产品规则或分析需求要求使用独立开关

可以采用混合建模,但如果设计实际描述的是少数几种命名预设,请避免堆叠大量独立选项。

选择方式
情况倾向使用
互斥布局(A 或 B,不可混搭)变体
设计使用命名预设或 Figma 变体变体
许多组合都无效或未经测试变体
产品需要任意混搭正交开关细粒度属性(或混合)
用户要求为每个维度提供独立控件细粒度属性

在分解交接文档中记录选择,以确保实现与 component.yml 保持一致。

交接文档和元数据中的属性顺序

确保分解交接文档和 component.yml 中的顺序一致,让 Canvas 编辑器能看到合理的表单流程。

  • 如果有一个主要的预设枚举,将其命名为 variant 并列在最前。
  • 然后列出内容属性(文案、链接、媒体)。
  • 最后列出其余配置属性(次要开关、样式辅助项)。

如果没有主要的 variant,则先列出内容属性,再列出配置属性。

如果没有单一的 variant,但模型总体上以预设为主,只要存在主要预设枚举,仍应将其列在最前。

Canvas 特定约束
  • 不要为可重复的富内容项使用对象数组属性。应使用父级插槽加子组件。
  • 属性面向编辑器。不要公开仅用于实现的值。
  • 必填属性不应依赖静默的实现默认值。元数据和编辑器应显式提供这些值。
  • 保持属性 ID 与其标签中的 camelCase 命名一致,并在 canvas-component-metadata 中确定最终的精确结构。
属性伪装成插槽的情况
  • 属性中包含 JSON 字符串或序列化块
  • 子 UI 使用对象数组

应将这些替换为插槽加子组件的组合方式。

插槽伪装成属性的情况
  • 插槽始终容纳一个具有固定属性的组件类型

在这些情况下,应考虑由父组件负责管理该标记,还是改用更精简的属性。

在 component.yml 中声明插槽

在 component.yml 中声明插槽,并通过框架的插槽机制使用它们(React 中使用命名属性;Vue 和 Astro 中使用命名插槽)。

有关精确的插槽架构和约束(映射还是 []、插槽键、children 的处理方式),请以 canvas-component-metadata 为准。

粒度检查

审核组件边界是过粗还是过细时,请使用这些启发式方法。先初步确定组件树和属性/插槽草案,再进行检查。目标是让编辑器能够理解每个组件,并让实例无需复制粘贴属性即可复用。

表明组件应进行拆分的迹象

如果组件存在以下情况,可以考虑拆分:

  • 有许多细粒度开关,但它们实际上描述的是少量命名预设,而不是彼此独立的选项。除非用户需要细粒度控制,否则优先使用变体。
  • 一个 machineName 负责互不相关的职责
  • 有 6-8 个以上用途各异的属性
  • 有适合作为独立组件的元素属性(面包屑、标题、元数据、导航)
  • 属性列表不断增长,且每个属性都对应一个视觉上独立的区块
  • 内置布局假设限制了组件的使用场景
  • 有多个可独立复用的不同视觉区块
  • 有重复的属性组,只在索引或前缀/后缀上有所不同(item1Title、item2Title、item3Title)
  • 布局包含多个可调整顺序的独立内容列
  • 父组件将布局外壳与多个独立内容区块混在一起
  • 用 showX/showY 链条来指定哪些子元素存在,而不是让作者直接放置子元素
常见的拆分模式
页面级元素应拆分为独立组件

如果某些元素会出现在多个页面上,但不一定总是一起使用,就应将它们拆分为独立组件。

将重复模式提取为小型组件

当相同的元素组合重复出现时,将其提取出来:

  • 日期 + 类别/标签 -> article-meta
  • 封面图片 + 下载按钮 -> resource-cover
  • 标签 + 值对 -> metadata-item
  • 图标 + 文本链接 -> icon-link
  • 网格/列表容器 + 重复卡片 -> card-grid + card
  • 特色汽车容器 + 重复汽车卡片 -> featured-cars-grid + car-card
使用布局组件,而非内置布局

不要将双栏或网格布局硬编码到内容组件中。使用布局组件,并将内容组合其中。

何时提取子组件

符合以下任一情况时,应提取子组件或添加插槽:

  • 该区块以相同角色出现两次或更多次
  • 该区块有明确的名称,也可能出现在网站的其他位置
  • 作者可能会独立调整、省略或替换该区块
  • 该区块将交互元素与静态相邻元素混在一起,导致父组件的职责不够清晰

典型的提取项:Meta、Actions、Media、Nav,以及列表或网格中的条目组件。

Canvas 编辑视角
  • 如果作者必须向某个区域放入任意区块,应使用插槽,而不是用属性来编码组件类型列表。
  • 如果文案是固定的营销文本,不需要组合内容,则适合使用字符串属性。
  • 如果组合形式仅限于一个可选的富内容区块,且类型始终不变,可以考虑将其保留在组件内部,或使用单个插槽,而不是设置许多微型插槽。

何时不应拆分

以下情况下应将组件保留在一起:

  • 在每种设计变体中,它们总是同时出现,且单独使用毫无意义
  • 它们共享大量内部状态,将状态提升到上层会很不方便
  • 视觉设计将它们紧密关联(例如,元素重叠、共享背景、蒙版)
  • 拆分后会产生只有 1-2 个属性、且无法在其他地方发挥作用的组件
细微信号(合并或转换)
  • 只包装单个标题或静态段落,且没有计划添加第二个实例的组件
  • 总是接收某种特定子元素且类型从不变化的插槽。如果结构固定,应合并到父组件中或替换为属性。
  • 唯一作用是在单个元素上设置 CSS 的包装组件。除非确实需要复用,否则优先使用父级布局或实用类。
反模式
  • 每个 div 一个插槽:每个 flex 子元素都变成插槽,却没有给作者真正的控制权。应按有意义的组合边界进行分组。
  • 属性透传开关:用许多布尔值控制本应拆分为独立子元素或插槽的区块
  • 万能布局:一个组件硬编码整个页面网格。优先使用布局组件和嵌套区域,而不是单体页面外壳。
重构循环
  1. 将每个不合格的节点标记为粗粒度、细粒度或创作不匹配。
  2. 对于粗粒度节点,拆分职责、为可变区域引入插槽,或提取重复项。
  3. 对于细粒度节点,合并节点、折叠插槽,或将固定结构移入父级实现中。
  4. 仅为边界发生变化的节点重新设计属性和插槽。
  5. 重新审核,直到通过或记录例外,并说明通常规则为何不适用。
词汇(可选)

原子、分子和有机体等术语可以描述规模,而非强制要求。 相比严格的原子化设计层级,应优先考虑复用、编辑器控制和 Canvas 约束。

评论

支持 Markdown