关于 canvas-component-composability
面向 Drupal Canvas 组件设计的组合性技能,帮助开发者规划 Props、插槽、变体和组件边界。强调可复用的布局与子组件组合,避免把重复内容压成复杂属性。
主要功能
- 01规划 Props 与插槽
- 02用变体表达预设样式
- 03采用父插槽与子组件模式
- 04评估组件拆分或合并
- 05遵循 Canvas 属性建模约束
适用场景
- 01设计可重复使用的卡片网格
- 02为 Canvas 编辑器规划组件控制项
- 03重构过多属性的组件
- 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 子元素都变成插槽,却没有给作者真正的控制权。应按有意义的组合边界进行分组。 - 属性透传开关:用许多布尔值控制本应拆分为独立子元素或插槽的区块
- 万能布局:一个组件硬编码整个页面网格。优先使用布局组件和嵌套区域,而不是单体页面外壳。
重构循环
- 将每个不合格的节点标记为粗粒度、细粒度或创作不匹配。
- 对于粗粒度节点,拆分职责、为可变区域引入插槽,或提取重复项。
- 对于细粒度节点,合并节点、折叠插槽,或将固定结构移入父级实现中。
- 仅为边界发生变化的节点重新设计属性和插槽。
- 重新审核,直到通过或记录例外,并说明通常规则为何不适用。
词汇(可选)
原子、分子和有机体等术语可以描述规模,而非强制要求。 相比严格的原子化设计层级,应优先考虑复用、编辑器控制和 Canvas 约束。