mcpField
Q
qt-figma-component-generation

qt-figma-component-generation

github.com/theqtcompanyrnd设计与 UI513441 次安装1 周前更新
代码仓库

关于 qt-figma-component-generation

该 Agent skill 根据 Figma 组件定义生成使用设计系统单例的 QML 控件,适用于 Qt UI 开发。它通过 MCP 获取设计规格,并提供两种组件实现模式及逐项生成流程。

主要功能

  1. 01通过 MCP 提取 Figma 组件规格
  2. 02生成 QML 控件文件
  3. 03支持内联与样式单例模式
  4. 04映射状态、变体与设计令牌
  5. 05维护组件清单与待办事项

适用场景

  1. 01将 Figma 按钮和输入框转为 QML
  2. 02按设计令牌构建一致的控件
  3. 03为多主题项目选择样式单例模式

MCP 相关

要求连接 Figma MCP,并使用 get_metadata 发现组件、get_design_context 提取组件设计信息。

安装

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

$npx skills add https://github.com/theqtcompanyrnd/agent-skills --skill qt-figma-component-generation

安装后在 Claude Code 中输入/qt-figma-component-generation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/qt-controls/
BadgeLabel.qml
BadgeLabelStyle.qml
BadgeNotification.qml
BadgeNotificationStyle.qml
Button.qml
ButtonStyle.qml
Card.qml
CardStyle.qml
CheckBox.qml
CheckBoxStyle.qml
ComboBox.qml
ComboBoxStyle.qml
Dialog.qml
DialogButtonBox.qml
DialogButtonBoxStyle.qml
DialogStyle.qml
IconButton.qml
IconButtonStyle.qml
Indicator.qml
IndicatorStyle.qml
ItemDelegate.qml
ItemDelegateStyle.qml
Label.qml
LabelStyle.qml
LinkInline.qml
LinkInlineStyle.qml
LinkList.qml
LinkListStyle.qml
LinkStandalone.qml
LinkStandaloneStyle.qml

详细介绍

Figma 组件生成技能

此技能通过 MCP 从 Figma 文件中读取组件定义,并生成可用于生产环境的 QML 控件文件,这些文件使用 Token 提取技能生成的设计系统单例。


前置条件

生成任何组件之前,请确认项目中存在以下所有内容:

  1. design-tokens.json — 来自 Token 提取技能的合并令牌文件
  2. QML 设计系统单例 — 位于 design-system/ 文件夹中的 Primitives.qml、Theme.qml、Spacing.qml、FontInterface.qml

如果缺少其中任何一项,请停止并先运行 Token 提取技能(qt-figma-token-extraction)。

确认 Figma MCP 已连接 — 确认工具列表中包含 get_metadata 和 get_design_context。如果没有,请告知用户:

“Figma MCP 连接器尚未连接。请通过 MCP 配置连接,然后回来继续。”

确认连接之前请勿继续。


步骤 1 — 组件发现

使用 get_metadata 获取文件结构,并确定哪些页面和画框包含组件:

Tool: get_metadata
Input: { "fileKey": "<file key>" }

从响应中记录所有作为组件组命名的页面和画框或组件集(例如 “Button”“Text Field”“Checkbox”)。

询问用户:

“我在 Figma 文件中看到以下组件组:[列表]。你希望我为哪些组件生成 QML 文件?还是全部生成?”

建立一张组件清单表,并在整个工作流中持续更新——之后不要再创建第二张表:

Figma 组件名称节点 IDQML 文件状态
Button67:139Button.qmlpending
Text Field...TextField.qmlpending

状态值:pending → extracting → mapping → done / blocked


步骤 2 — 选择模式

在读取任何资源或编写任何代码之前,请让用户选择一种实现模式。如果 AskUserQuestion 工具可用,请使用它:

tool: AskUserQuestion
question: "Which code style should the generated components use?"
options:
  - "Pattern A — Inline (self-contained file, all state logic inside the component)"
  - "Pattern B — Style singleton (ComponentStyle.qml + Component.qml, supports multiple themes)"
  - "I'm not sure — recommend one"

如果该工具不可用(例如在 Claude Code、Codex 或 Copilot 中),请以纯文本提问,并等待用户回复后再继续。

如果用户选择“我不确定”,对于大多数项目,建议使用 模式 A——它更简单、独立性更强,也更易于调试。只有当项目已有 Qt.Themes / TokenInterface 层,或需要支持多种可切换主题时,才建议使用模式 B。

模式 B 使用整数枚举变体,而不是字符串。 模式 A 使用 property string variant: "primary"。模式 B 使用 property int typeVariant: ButtonStyle.TypeVariant.Primary。不要混用这两种方法——选择其中一种,并在所有组件中始终如一地使用。


步骤 3 — 准备所选模式

在提取或编写任何内容之前,请确保所选模式的结构已准备就绪。模式 B 从随附资源中读取;模式 A 则使用步骤 5 中的内嵌片段构建。

Pattern A 资源 — references/

此文件夹包含经 Figma 验证的 Pattern A 控件。每个文件都是独立的,所有状态逻辑都在组件内部通过对 readonly property 值使用条件表达式实现。

参考文件输出文件演示内容
references/Button.qmlButton.qmlAbstractButton、多变体状态机、尺寸辅助项、强调色系列映射
references/TextField.qmlTextField.qml在 ColumnLayout 中包装的 TextInput、标签 + 错误 + 辅助文本、清除按钮
references/Checkbox.qmlCheckbox.qmlCheckBox 指示器、Canvas 勾选标记、不确定状态
references/Toggle.qmlToggle.qmlSwitch 轨道 + 动画滑块、NumberAnimation
references/Select.qmlSelect.qml带 Popup 的自定义 Item、ListView 委托、箭头

编写代码前,请先阅读与正在生成的组件最相符的文件。 如果有 QML 编码技能(qt-development-skills:qt-qml)可用,编写时请使用它,以确保输出符合 Qt 6 的惯用模式。

Pattern B 资源 — assets/qt-controls/

此文件夹包含来自生产级 Qt 控件库的 QML 文件对。每个组件拆分为两个文件:

  • Button.qml — 组件逻辑、布局、基类型、公共 API
  • ButtonStyle.qml — 定义各状态和尺寸变体的类型化 component 对象的 pragma Singleton

编写代码前,请先阅读即将生成的组件对应的资源文件对。 生成的文件必须遵循参考资源的结构、属性顺序和模式选择。如果输出与参考资源不一致,且无法用特定的 Figma 组件来解释,请思考原因并进行修正。存在参考资源时,不要另行设计不同的结构。

请先阅读以下核心文件对(阅读与正在生成的组件对应的文件对):

  • Button.qml + ButtonStyle.qml
  • CheckBox.qml + CheckBoxStyle.qml
  • ComboBox.qml + ComboBoxStyle.qml
  • Switch.qml + SwitchStyle.qml
  • TextField.qml + TextFieldStyle.qml

第 4 步 — 按组件提取

针对清单中的每个组件,通过 MCP 提取其规格。

始终对单个主组件节点调用 get_design_context,而不是对父组件集节点调用。 组件集会返回包含所有变体的超大 JSON。先检查默认/基础变体,再分别检查有代表性的变体(Hover、Pressed、Disabled)。

Tool: get_design_context
Input: { "fileKey": "<key>", "nodeId": "<individual component node id>" }

如果尚未获取单个节点 ID,请对父级框架调用 get_design_context 并查找子组件节点,然后再对每个节点重新调用。

每个组件需要提取的内容
  • 变体 / 属性 — Figma 变体属性及允许值 → QML property 声明
  • 状态 — Default、Hover、Pressed、Disabled、Focus、Error → 对 readonly property 值使用条件表达式
  • 尺寸 — 高度、内边距(水平 + 垂直)、间距、字号、字重、圆角半径
  • 颜色令牌 — 各状态中出现的语义令牌;记录 Figma 中的确切名称及其在 design-tokens.json 中解析出的值
  • 排版 — 每个文本元素的字体系列、字号、字重、行高
  • 边框 — 描边宽度、颜色令牌、出现此边框的状态
  • 图标 / 插槽 — 组件是否包含图标插槽、插槽尺寸、位置(左侧/右侧/两侧)

编写代码前,将所有提取的数据记录在临时笔记中。


第 5 步 — Figma → QML 映射

引用任何令牌前,请先打开 Theme.qml、Primitives.qml、Spacing.qml 和 FontInterface.qml,并阅读实际的属性名称。 不要从参考资源中复制令牌名称 — 项目的令牌命名规范可能与示例不同。组件中编写的每个令牌名称都必须存在于项目的单例中。

基础类型选择
Figma 组件QML 基础类型
按钮(任意样式)AbstractButton(来自 QtQuick.Controls)
复选框CheckBox(来自 QtQuick.Controls.Basic)
单选按钮RadioButton(来自 QtQuick.Controls.Basic)
切换开关Switch(来自 QtQuick.Controls.Basic)
文本输入框/字段用 Rectangle + TextInput 包装的 ColumnLayout
文本区域(多行)用 TextArea(来自 QtQuick.Controls.Basic)包装的 ScrollView — 暂无参考资源;遵循 TextField 模式,但添加 wrapMode: TextArea.Wrap 并移除固定高度
选择框/下拉菜单带 Popup 的自定义 Item
滑块Slider(来自 QtQuick.Controls.Basic)
标签栏TabBar + TabButton
进度条ProgressBar(来自 QtQuick.Controls.Basic)
微调框/数值微调框SpinBox(来自 QtQuick.Controls.Basic)
卡片/容器Rectangle 或普通 Item
分隔线Rectangle(1 px,fillWidth)
徽标包装 Text 的 Rectangle
工具提示ToolTip(来自 QtQuick.Controls.Basic)
变体 → 属性模式(模式 A)
property string variant: "primary"   // primary | secondary | ghost | tertiary | danger
property string size:    "medium"    // small | medium | large  (sm | md | lg accepted)
变体 → 枚举模式(模式 B)
// Use integer enums, not strings — do not mix with Pattern A string variants
property int typeVariant: ButtonStyle.TypeVariant.Primary
状态 → 条件表达式模式
readonly property color _bg: {
    if (!enabled) return Theme.background_muted
    return pressed ? Theme.accent_subtle
         : hovered ? Theme.accent_muted
         :            Theme.accent_default
}
图标槽模式
// Icon slot — rendered via icon font glyph in a Text item
property string iconGlyph:     ""
property int    iconLayoutDir: Qt.LeftToRight   // Qt.LeftToRight | Qt.RightToLeft
                                                 // controls which side the icon appears on

contentItem: RowLayout {
    layoutDirection: root.iconLayoutDir
    spacing:         root._iconGap
    Text {
        text:        root.iconGlyph
        font.family: FontInterface.iconFont.name
        visible:     root.iconGlyph !== ""
    }
    Text {
        id:   _label
        text: root.label
        // ... font properties
    }
}
尺寸 — 优先使用令牌,必要时使用字面值

首先检查 Spacing.qml 和 FontInterface.qml。只有在没有令牌涵盖相应尺寸时,才使用字面值,并添加 // TODO: add to Spacing.qml 注释。

焦点环模式

焦点环仅适用于基于 Control 的组件(AbstractButton、CheckBox、Switch、Slider 等)。Text Field(根类型为 ColumnLayout)和 Select(根类型为 Item)不是 Control 子类 — 对它们使用 activeFocus 和固定半径。

// For Control-based components (AbstractButton, CheckBox, Switch …)
Rectangle {
    anchors { fill: parent; margins: -2 }
    radius:       parent.radius + 2          // only valid when parent is a Rectangle
    color:        "transparent"
    border.color: Theme.stroke_focus         // use a token — never a literal color
    border.width: 2                          // TODO: promote to Spacing token if available
    visible:      root.visualFocus           // Control property — gives keyboard-only focus ring
}

// For non-Control roots (ColumnLayout, Item) — use activeFocus and fixed radius
Rectangle {
    anchors { fill: parent; margins: -2 }
    radius:       4                          // TODO: use Spacing token
    color:        "transparent"
    border.color: Theme.stroke_focus
    border.width: 2
    visible:      root.activeFocus
}
颜色动画模式

仅在交互期间(悬停、按下)会发生动画的颜色属性上添加 Behavior 块。禁用状态下跳过这些块 — 此时通常应直接切换,而不是渐变。

// On the Rectangle or contentItem that holds the interactive color:
Behavior on color        { ColorAnimation { duration: Theme.duration_fast } }
Behavior on border.color { ColorAnimation { duration: Theme.duration_fast } }
// If no duration token exists yet: duration: 100 — add a TODO to promote it
光标模式
HoverHandler { cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor }

步骤 6 — 编写 QML 文件

将每个组件放在项目的 components/ 文件夹中。使用与 Figma 组件名称一致的 PascalCase 命名(Button.qml、TextField.qml 等)。

文件头
// ComponentName.qml — [Project] Design System — [component description]
// Maps to Figma: [file name] → [component name] (node [id])
//
// Figma variants (inspected via MCP, [date]):
//   Prop1: "value1" | "value2"
//   Prop2: "valueA" | "valueB"
// States: Default | Hover | Pressed | Disabled [| Error | Focus]
// Sizes:  "small" | "medium" | "large"
//
// Usage:
//   import MyProject
//   ComponentName { prop: "value"; onAction: doThing() }
公共 API 部分
// ── Public API ────────────────────────────────────────────────────────────
property string variant: "primary"
property string size:    "medium"
property string label:   "Button"

// ── Private helpers ───────────────────────────────────────────────────────
readonly property bool  _isSmall: size === "small" || size === "sm"
readonly property color _bg: ...
缺失值
// TODO: add Spacing.buttonIconGapSm to Spacing.qml (Figma: 0px for small buttons)
readonly property int _iconGap: _isSmall ? 0 : Spacing.x4

生成所有组件后,为用户汇总完整的 TODO 列表。


步骤 7 — 生成后检查

编写完所有组件后,进行一次一致性检查:

  • 每个引用主题令牌的 readonly property color 都必须使用 Theme.qml 或 Primitives.qml 中实际存在的名称。标记出不存在的名称。
  • 每个数值尺寸都必须来自 Spacing.qml 或 FontInterface.qml。收集所有应提升为令牌的字面值。
  • 每个交互式组件都有焦点环。
  • 每个交互式组件都有带光标形状的 HoverHandler。
  • 文件头记录已检查的节点 ID。
  • 更新步骤 1 中的清单表格 — 将所有组件标记为 done 或 blocked。

向用户简要汇报:

  • 已生成的组件(数量和名称)
  • 已跳过或受阻的组件(及原因)
  • 完整 TODO 列表:需要添加到设计系统单例中的令牌
  • 建议的下一步:将组件添加到 CMakeLists.txt 中的 qt_add_qml_module QML_FILES,并在组件展示页中进行冒烟测试

常见陷阱

检查组件集,而不是主组件。 组件集会堆叠显示所有变体。务必深入查找单个组件节点。

使用参考资源中的令牌名称,而不是项目中的名称。 参考资源使用的示例令牌名称可能与项目的单例不匹配。务必先读取实际的单例文件。

将令牌中已有的值硬编码。 编写任何数字字面量之前,先检查 Spacing.qml 和 FontInterface.qml。

遗漏不确定/部分选中状态。 复选框和单选按钮通常有第三种状态。务必检查 Qt.PartiallyChecked。

未将 AbstractButton 的默认内边距设为零。 AbstractButton 和其他 Control 子类有默认内边距,会增加渲染高度。自行管理几何属性时,请显式将内边距设为零。

忘记 Behavior 块。 对交互期间会变化的颜色属性(悬停、按下)添加 Behavior on color { ColorAnimation { duration: Theme.duration_fast } }。时长请使用令牌,不要硬编码为 100。禁用状态下不要添加 Behavior;此时通常应直接切换。

Popup 的 z 轴顺序。 如果 Popup 项被父容器裁剪,需要设置 parent: Overlay.overlay。

混用模式 A 字符串和模式 B 枚举。 选择一种变体实现方式,并在所有组件中保持一致。

评论

支持 Markdown