TDesign Flutter 通用协作约定,适用于仓库开发和 PR 工作,涵盖 Spec、更新日志、公开契约、生成产物、双版本及 CI 登记。组件对齐由 Review skill 补充,CNB 平台限制见仓库协作说明。
日本語の概要は準備中です。原文の説明を表示しています。
Review TDesign Flutter 组件的公开 Demo、API 收敛、Flutter 设计模式、主题、测试和 Golden 证据。以小程序公开 Demo 作为可见效果参考,但不机械映射其 props/events;适用于组件对齐和 PR Review。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
依据当前 PR 的实际源码、运行结果和测试进行 Review。仅请求 Review 时只审查;已获授权的修复或 PR 更新按约定范围继续执行,不重复索取许可,也不从 Review 请求推导修改权限。
本 skill 只补充组件对齐专项规则。分支、Spec、更新日志、双版本兼容、lint 和 PR 模板仍以仓库 CONTRIBUTING.md、specs/README.md 与 tdesign-flutter-general 为准。仓库 .agents/skills/tdesign-component-align-review/SKILL.md 是唯一维护源,外部安装副本只做镜像,不得独立演化。
使用外部镜像时,文中的仓库文件和相邻 skill 引用均从目标仓库对应路径解析,不从本机安装目录寻找仓库规范。
记录实际 checkout、Flutter PR 的 base、head、commit 和改动文件。涉及跨端 Demo 时,同时记录小程序版本或 commit、公开 Demo 入口及直接使用的模板、样式和脚本;不要把本地过期分支或单个截图当成当前基准。
区分实现事实与对齐目标:当前 Flutter 源码、运行和测试用于判断实际行为;目标以用户指定的设计稿、版本或契约为准,未指定时参考小程序公开 Demo。两者不一致时记录偏差,不以现状替代目标。跨端参考的取证顺序:
单张截图、首屏、测试覆盖率或 API 列表不能证明 Demo 完整性。无法运行或测量的内容标为未验证,不得写“完全一致”。
按第 1 节确定的目标逐实例核对;默认采用小程序公开页面顺序:
以官方公开页面中的 Demo 块为契约边界:ExampleModule / ExampleItem 表达公开分组、标题、描述和示例顺序,不按每个内部 Widget 机械拆分。Flutter 多余示例应删除;仍有测试价值的场景移入聚焦 Widget 测试。同步 Demo 源码、生成示例、页面测试和必要 Golden。
Demo 展示组件能力,不替组件补实现或修复默认样式:
TButton、TText、TPopupHeader、TPopup;不以 Material 控件的默认视觉替代。Demo 自行编写的布局使用 Row、Column、Padding、SizedBox、Expanded 等基础原语,只负责外部排列和合理约束。Material 包装、装饰、位移或样式覆盖来掩盖缺陷。明确展示自定义样式的示例可用已有 API 或 Theme,但不能替代默认样式验收。TPopup + TPicker 的草稿、确认、取消和可用高度;状态/API 的归属遵循第 3 节。此规则不禁止导入 material.dart 或使用 Flutter 基础机制;显式主题覆盖遵循第 4 节。“假组件符合”是指 Demo 通过外层样式或约束修正组件本应自己负责的视觉,导致截图看似对齐、但组件脱离该 Demo 或换用正常约束后仍不符合。逐个公开 Demo 检查组件的直接参数和祖先 Widget,并将每个外层样式归类为以下三种:
Row、Column、Expanded、Padding、SizedBox、滚动容器等仅用于排列组件与示例内容,或提供页面所需的合理约束;右侧内容的背景、分隔线、图片尺寸和文本排版属于内容自身,不是组件样式补丁。Material、DecoratedBox、Container 装饰、DefaultTextStyle、IconTheme、Theme、MediaQuery、Transform、透明度、阴影、圆角、颜色、位移,或特殊 padding / 尺寸来复制组件内部背景、字体、选中态、指示器、边框、圆角、间距和对齐,或掩盖溢出、状态和交互缺陷。此类用法应定位为 Demo 缺陷或组件内部缺陷,不能以截图“看起来一致”通过 Review。默认样式 Demo 必须直接使用组件默认参数 / 组件 Theme,并在相同页面约束下检查组件实际解析出的样式;发现疑似补丁时,记录组件调用、祖先布局、运行表现和最小修复归属。不能仅凭 Golden 或首屏截图判断无补丁,也不能把合法的外部内容布局误报为组件样式覆盖。
默认 Demo 中确认会改变组件视觉契约的外层样式补丁属于阻塞问题:应优先修复组件 / 组件 Theme,或移除错误的 Demo 样式;只有明确的自定义样式示例才可保留这类覆盖,并且不能替代默认 Demo 验收。
页面壳及可复制示例按以下规则处理:
ExamplePage.compactDemo;不要在每个 builder 中重复绘制背景,也不要仅为单个组件扩展 ExampleItem。TCellGroup 管理背景、分隔线和末项边界,不在 Demo 中重复编写 Column + Divider。状态子标题仍按官方页面层级放置,不能为了代码短而改变背景层级。先判断缺口层级,再决定修改方式:
| 层级 | 判断 | 优先处理 |
|---|---|---|
| Demo 缺口 | 组件已有能力,但父布局约束或组合错误 | 修正 Example;如弹层未给标题预留高度 |
| 内部缺口 | 公开契约足够,但组件在合理约束下仍异常 | 修复组件并补组件测试;如 TD 标题继承错误装饰,不在 Demo 包装补救 |
| API 缺口 | 公开 Demo 或已验证的 Flutter 真实用例无法由组合、Theme 或现有 API 合理表达 | 提出最小公开 API;仅在超出既有授权或需要用户决策时确认 |
| 无缺口 | Flutter 已有等价表达 | 不修改 API |
| 候选能力 | 仅见于上游 API 表,公开 Demo 未使用且没有已验证的 Flutter 真实用例 | 只记录,不实现 |
禁止为了 API 一一对应、缩短 Demo 代码或补齐上游 props/events 而扩大 Flutter 公共面。
不能只检查本次新增字段。结合组件当前全部公开构造参数、字段、回调、枚举、Controller 和 ThemeData,回答“API 是否已收敛”,并列出证据:
| API/组合 | 状态源和实际语义 | 重叠或冲突 | Flutter 惯用表达 | 结论 |
|---|---|---|---|---|
| 示例 | 默认值、空值和生效条件 | 独立/重复/别名/冲突 | 参数、nullable callback、Widget、builder、Theme 或 Controller | 保留/合并/改名/删除/待确认 |
必须检查:
先确定公开 API 的单一状态源,再决定内置默认样式从哪里取得;不得反过来为了 token 化扩大公共面:
variant、colorPreset、status 与 Theme 的判定模型TButton 只提供职责拆分参考,不是所有组件枚举取值的命名模板。Web / 小程序的 theme、type 等名称不能机械映射;必须根据调用者意图和运行效果判断维度,再记录枚举全部取值、默认值、空值语义、有效组合和公开字段类型。
| 维度 | 判定标准 | 示例 | 所有权 |
|---|---|---|---|
variant | 改变结构、布局、边框或填充/描边等绘制处理;不是任意色相切换 | fill / outline / text / ghost、solid / tinted、linear / circular | 实例 API;满足严格条件时 Theme 可提供 defaultVariant |
colorPreset | 业务含义和绘制处理不变,只选择一组协调的内置预设颜色,不传入实际 Material ColorScheme | defaultTheme / primary / danger,以及组件确有需要的其他调色预设 | 仅实例 API;Theme 不保存该选择器 |
status / state | 表达组件、内容或数据当前所处的业务或生命周期状态 | normal / info / success / warning / error、ready / uploading | 实例、数据模型或 Controller 中唯一合适的一处;Theme 不拥有状态 |
style / 具体样式字段 | 完整或局部覆盖最终呈现 | ButtonStyle、颜色、文字样式、间距 | 实例完整 style 或组件 Theme;不得再造同义选择器 |
按以下顺序判定,不能只看枚举成员名称:
status / state,即使当前实现暂时只改变颜色。variant。例如同一组件的实色、浅色填充和描边可以是不同 variant。colorPreset。因此 info / success / warning / error 既不能一律判为状态,也不能一律判为配色:输入框校验、上传进度或公告状态属于 status;Tag 或 Popover 若只是由调用者选择内置配色、没有状态行为和默认内容语义,可以属于 colorPreset。light 也不是固定维度:表示浅色填充处理时属于 variant,表示一套独立配色时才属于 colorPreset。dartdoc 必须写清实际语义,不能让调用者依赖猜测。
Theme 与默认值遵循以下所有权规则:
colorTheme,也不得在组件 ThemeExtension 中保存组件枚举型 colorPreset、defaultColorPreset、status 或 defaultStatus。Flutter 官方 ThemeData.colorScheme 与类型 ColorScheme 是 Material 实际调色板,不受此限制;内部私有/常量形式的内置默认配色也不是 Theme 选择器。Color、TextStyle、ButtonStyle、布局值和按状态派生的样式。resolve(context, status: instanceStatus) 接收实例状态计算样式不表示 Theme 拥有状态;Theme 不得自行选择或覆盖当前状态。variant 为 nullable 时,才可提供 defaultVariant。解析顺序必须是 instance.variant ?? theme.defaultVariant ?? builtInDefault。实例已经使用非空内置默认值时,不再增加 Theme defaultVariant 形成第二默认源。colorPreset 与 status 不提供 Theme 回退,使用实例值或组件内置默认值。枚举成员词汇按组件语义决定;Button 的取值不是强制全集。已发布的 defaultTheme 等名称保持兼容,重命名必须按 breaking change 处理。variant、colorPreset、status 彼此独立且至少存在两组有意义的交叉组合时,才同时公开。若组合被禁止、没有真实用例或一个维度可由另一个推导,则合并或只保留权威入口。以下情况默认视为冗余:
enableX 与 onX != null 同时控制能力;disabled 与 nullable callback 重复表达禁用;未发布的冗余 API 直接收敛;已发布 API 必须说明 breaking 风险和迁移方式。没有逐项证据时,不得断言“API 已完全收敛”或“符合 Flutter 设计模式”。
API Review 不以“字段有一句 dartdoc”为完成。对本次新增、修改或用于表达公开 Demo 的每项公开契约,建立“公开行为 → 实现与测试 → 源码 dartdoc → 生成 API / 可复制示例”的对应关系,并检查用户是否无需阅读实现即可正确使用。至少覆盖:
variant、colorPreset、style、Theme 与实例参数各自职责及字段级覆盖优先级;源码 dartdoc 是文档事实源,但必须运行仓库 API 生成器并检查实际生成产物;只在 IDE 注释中清楚、生成 API 中丢失仍判为未完成。特别核对生成器选取的是构造参数还是字段注释,避免同一参数的短注释覆盖完整契约。生成成功或产物同步只证明生成链路可用,不证明内容覆盖完整。
文档只描述用户可观察的公开契约,不暴露私有类、内部算法或仅服务 Demo 的常量。本次变更涉及的公开行为若缺少上述说明,或生成示例无法让用户复现,属于阻塞问题;与当前范围无关的历史文档缺口单独登记,不扩大无关 PR。不要用仅匹配关键词或固定文案的测试冒充文档完整性验证。
TD 内置视觉和行为字段的解析优先级为:实例显式参数或受支持的完整 style > 当前子树的 TD 组件 ThemeExtension 显式字段 > TDesign 语义 token / 已文档化的内置默认值。外部 Material/M2/M3 默认及显式主题不作为 TD 视觉或行为入口;实例 style 可以复用 Flutter 样式类型,但不因此开放 Material 主题继承。child、prefix、suffix、builder 等调用方内容保留自身的主题行为,内部隔离不得覆盖用户内容树。原生选择与编辑、Tooltip、反馈及焦点、键盘、无障碍能力继续支持,但其可配置行为和视觉由 TD 明确,不透传外部 Material 主题;不将其使用 Material 实现本身判为样式泄漏。亮暗模式、字体缩放、平台输入、焦点、键盘、方向与无障碍机制继续支持。第 3 节的语义选择器不套用视觉解析链。
TText、TLoading 等子组件继承当前 Theme 子树,不接收子组件 ThemeData;视觉优先级按字段生效;样式对象非空不表示全部字段均为显式覆盖。Flutter 默认主题生成、copyWith / apply 补全、TDesign Theme 投影和继承链带入的值仍属于默认来源。
style、便利参数或其他高优先级入口回传给子组件,否则会把默认值伪装成实例显式覆盖;ThemeExtension 的配置值、运行时有效值和插值值必须使用同一默认语义。nullable 字段以 null 表示内置默认值时,lerp 使用运行时有效默认值,不能把 null 当作 0、空颜色或其他无关初值;两侧均为 null 时保持 null。
copyWith、lerp、dartdoc 和测试;null、端点与中间值,以及动态 Theme 切换后的实际呈现。默认值优先复用 TDesign 语义 token;无匹配 token、无子树默认需求且共享 token 缺少复用证据时,可保留单一、已文档化且有契约证据的内置默认值。不得借用无关 token 或只为消除字面量新增 Theme 字段。公开字段归属仍按第 3 节判断。
0、数量、最大行数、枚举值和无量纲绘制比例不属于样式 token。固定路径坐标或数值一旦决定可见尺寸、间距、圆角或描边,仍按样式值审查;几何比例应从画布、控件尺寸或 token 派生。组件整体 Review 必须同时检查运行中的 Demo 和用户实际打开的“查看代码”内容。仓库里存在完整源码,不等于代码面板已展示完整示例;此项适用于所有公开示例,不只适用于弹层组件。生成机制与命令以通用 skill 第七节为准。
检查路径:逐个公开 Demo 确认 ExampleItem / builder → 实际代码入口(含 methodName 等覆盖配置)→ 生成片段 → 面板呈现内容,再追踪片段引用的辅助方法、数据和状态。不能假定生成器递归收集调用依赖,也不能只检查 @ExampleCode 是否存在。仅改变入口名称或给辅助方法加注解,不代表依赖已经齐全。
完整性边界:示例应让用户理解并复现它声称演示的能力,允许采用以下两种明确形式:
无论采用哪种形式,当前演示能力的关键逻辑不能只藏在链接或未展示的私有方法中:
value / onChanged 参数名,不能证明受控示例可复现。_cell、_showPicker、_values 等引用。参数化方法必须说明调用处如何提供数据和回调,不能只把隐藏状态改为未说明的参数。例如,Picker 面板仅展示 TCellGroup(cells: [_cell(...)]) 时缺少核心能力;仅改为展示 _showPicker(items, value, onConfirm),却未说明触发入口、数据和状态回传,也仍不完整。应展示真实的触发与 TPopup + TPicker 组合,以及草稿、确认和取消的状态关系;这不要求 Picker 自身拥有 Popup。
验证与记录:
--check;生成片段不得手工修改。--check 只证明源码与产物同步,不证明依赖完整、能编译或行为正确。缺陷判定:按第六节的严重性规则,当前范围内的错绑、缺失、核心行为隐藏、无法解析的必要依赖、源码与展示行为不一致,或声称可运行却不能编译/复现,属于示例交付缺陷。组件整体验收或本次修改的示例不得以“仓库以前也这样写”为理由降为建议;与局部 PR 无关的历史示例缺陷单独登记,不阻塞无关改动。合理省略通用壳、已说明的数据集引用和纯排版改进不自动构成阻塞。缺陷应定位到源示例或映射配置,并明确是示例展示问题还是组件运行问题,不能从展示不完整推导组件 API 有缺口。
新增或修改组件测试、Demo 功能测试与 Golden 后,按 tdesign-flutter-general 第八节 核对登记、自测与真实 CI 入口。区分已登记、本地已通过和远端 CI 已通过,不以 job 名称代替执行证据。
当前 PR 新增或修改的组件测试、覆盖率目标或 Demo Golden 未登记到仓库已有 CI 调度入口时,属于测试门禁缺失,Review 判定为阻塞问题;不得降级为仓库既有基础设施建议。
共享测试文件可能被多个组件清单重复调度。失败归因以实际测试文件、测试名称、失败像素和差异图为准,不以调度器的组件标签或汇总名称推断多个组件同时回归;报告时区分真实受影响组件与重复呈现的同一失败。
验证以“变更批次”和当前源码指纹为单位,不按每次保存文件或每个小改动自动重复运行。先根据 git diff --name-only 和实际影响判断门禁范围:
| 变更范围 | 实现阶段优先验证 | 稳定后是否需要 Golden |
|---|---|---|
| 逻辑、状态、回调、API、测试或注释 | 受影响的聚焦功能 / Widget 测试,必要时 analyze 和生成器 --check | 不涉及视觉时跳过 |
| 组件绘制、Theme、Demo 布局、字体、图标或资源 | 先完成上行的功能门禁,再运行受影响的非视觉回归 | 仅在视觉确实受影响时运行 |
| 依赖、SDK、公共 Theme 或共享基础设施 | 按依赖链扩大到对应包 / 双版本门禁 | 由实际视觉影响决定 |
遵循以下执行顺序:
git diff --check、生成产物 --check(若适用)和受影响功能测试,再一次性运行本次范围所需的完整非视觉门禁。把测试结果关联到当前源码 / diff 指纹;指纹至少包含验证基线到当前提交的二进制 diff(可用 git diff --binary --no-ext-diff <base>...HEAD -- <受影响路径> | shasum -a 256 记录)以及 Flutter SDK、依赖、字体/资源、主题环境和测试命令。上述任一项变化都会使检查点失效,必须重新走对应层级。变更范围可先用 git diff --name-only <base>...HEAD 分流:命中 tdesign-component/lib/src/ 或 test/components/ 时跑受影响组件 Widget 测试及组件回归;命中 example/lib/ 或 example/test/ 时跑对应 Demo 功能测试与生成器 dart run tool/generate_example_code.dart --check;命中 tool/component_test_manifest.dart、视觉测试或 Golden/字体资源时,再纳入对应 visual runner。组件源码、Demo、Theme、字体或 Golden 变化稳定前只跑功能门禁,稳定后才执行一次无参 Golden 比对;清单登记、本地通过和远端 CI 通过分别记录,不能互相替代。
本地验证是分层证据,不替代远端 CI;报告必须写明实际运行的层级、命令、版本和是否跳过 Golden 的原因。Golden 不是所有代码变更的必经步骤,但对已确认的视觉变更也不能用功能测试替代。
ExampleItem / 场景 → 初始或操作后稳定可见状态 → 真实触发步骤 → 是否存在实质视觉差异 → light/dark Golden → 功能测试 → 未单独截图时的等价覆盖依据”。场景清单从实际公开页面和目标设计取得,不能只从现有 Golden 文件反推。ExampleItem / 分组边界分别截图,或生成完整滚动页面证据;仅覆盖首屏不能宣称整页齐备。Review 输出按严重程度列出问题,每项包含文件行号、可复现行为、根因、影响、最小修复和应补测试。明确区分:
先判断缺失证据是否属于本次验收范围:完成当前行为、API、视觉或兼容性契约所必需的证据缺失时,必须列为阻塞问题;只有明确超出本次范围,或不影响当前契约且因环境限制无法补充的证据,才列为非阻塞的未验证项。不得用“未验证”绕过本 skill 的完成条件。
当 Review 没有阻塞问题时,结论为通过;除非用户明确要求,不修改 PR。用户明确要求创建或更新 PR 时,PR 模板、更新日志和 breaking 格式遵循仓库 CONTRIBUTING.md、PR 模板及 tdesign-flutter-general,本 skill 只补充以下对齐 Review 专项要求:
CI 自动修复、合并冲突、生成产物回写或机器人提交都会产生新的 Review head。旧 head 上的 CodeBuddy、人工 Review、CI 或本地验证不能直接作为新 head 的通过证据;先检查自动提交的真实 diff,再对最终 head 重跑受影响门禁并重新请求所需 Review。autofix 显示成功时仍须确认它没有删除或回退本次公开契约。
当 Review 有阻塞问题时,不得用改标题、正文、Golden 容差或更新基线规避问题;仅审查任务报告问题,已授权修复的任务继续修复。修复后基于最新代码及验证证据重新判断,不能沿用旧结论。
按本次任务范围判断完成:公开 Demo 契约有证据;缺口分层正确;API 无重复状态源且符合 Flutter 模式;Theme 继承合理;相关非视觉测试、必要的 Golden(仅视觉影响时)以及双版本 analyze 和必要覆盖率按执行门禁通过。涉及 PR 时还需核对标题与描述是否准确;存在未获授权的修改需求应报告,不能据此自行修改远端。
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
TDesign Flutter 通用协作约定,适用于仓库开发和 PR 工作,涵盖 Spec、更新日志、公开契约、生成产物、双版本及 CI 登记。组件对齐由 Review skill 补充,CNB 平台限制见仓库协作说明。
日本語の概要は準備中です。原文の説明を表示しています。