figma-cache-toolchain 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -170
- package/cursor-bootstrap/AGENT-SETUP-PROMPT.md +75 -43
- package/cursor-bootstrap/examples/README.md +26 -15
- package/cursor-bootstrap/examples/ui-adapter.contract.template.json +90 -0
- package/cursor-bootstrap/examples/ui-execution-template.fast.md +11 -0
- package/cursor-bootstrap/examples/ui-execution-template.strict.md +13 -0
- package/cursor-bootstrap/examples/ui-override.template.json +26 -0
- package/cursor-bootstrap/figma-cache.config.example.js +51 -9
- package/cursor-bootstrap/managed-files.json +40 -40
- package/cursor-bootstrap/skills/figma-ui-dual-mode-execution/SKILL.md +55 -37
- package/figma-cache/adapters/recipes/button.recipe.json +24 -0
- package/figma-cache/adapters/recipes/card.recipe.json +24 -0
- package/figma-cache/adapters/recipes/checkbox.recipe.json +24 -0
- package/figma-cache/adapters/recipes/input.recipe.json +24 -0
- package/figma-cache/adapters/recipes/modal.recipe.json +25 -0
- package/figma-cache/adapters/recipes/radio.recipe.json +23 -0
- package/figma-cache/adapters/recipes/select.recipe.json +24 -0
- package/figma-cache/adapters/recipes/table.recipe.json +25 -0
- package/figma-cache/adapters/recipes/tabs.recipe.json +24 -0
- package/figma-cache/adapters/recipes/tooltip.recipe.json +24 -0
- package/figma-cache/docs/README.md +323 -237
- package/figma-cache/docs/p0-ui-preflight-handoff.md +207 -0
- package/figma-cache/docs/ui-1to1-optimization-roadmap.md +182 -0
- package/figma-cache/docs/ui-1to1-report.schema.json +104 -0
- package/figma-cache/figma-cache.js +639 -562
- package/figma-cache/js/contract-check-cli.js +466 -0
- package/figma-cache/js/cursor-bootstrap-cli.js +22 -0
- package/figma-cache/js/ui-facts-normalizer.js +233 -0
- package/package.json +93 -73
- package/scripts/cross-project-e2e.js +594 -0
- package/scripts/ui-1to1-audit.js +431 -0
- package/scripts/ui-auto-acceptance.js +248 -0
- package/scripts/ui-preflight.js +289 -0
- package/scripts/ui-profile.js +46 -0
- package/scripts/ui-report-aggregate.js +124 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"scope": "node",
|
|
4
|
+
"description": "Node-level override for exceptional visual/interaction differences.",
|
|
5
|
+
"tokenMappings": [
|
|
6
|
+
{
|
|
7
|
+
"id": "node.token.override.example",
|
|
8
|
+
"figmaToken": "Example/Primary",
|
|
9
|
+
"figmaValue": "#305AFE",
|
|
10
|
+
"required": false,
|
|
11
|
+
"projectBinding": {
|
|
12
|
+
"type": "literal",
|
|
13
|
+
"value": "#305AFE",
|
|
14
|
+
"notes": "Only use when this node truly differs from global contract."
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"stateMappings": {
|
|
19
|
+
"select": {
|
|
20
|
+
"requiredStates": ["default", "expanded", "selected", "unselected"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"layoutRules": [],
|
|
24
|
+
"typographyRules": [],
|
|
25
|
+
"interactionRules": []
|
|
26
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
2
|
* 项目级 Figma 缓存扩展(示例模板,**不绑定任何 UI 框架**)。
|
|
3
3
|
*
|
|
4
4
|
* 安装本 npm 包并执行 `npx figma-cache cursor init` 后,项目根会出现 **AGENT-SETUP-PROMPT.md**:
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* 若你已有 `figma-cache.config.js`,可由 Agent 合并而非覆盖。
|
|
8
8
|
*
|
|
9
|
-
* 加载顺序见 `figma-cache/figma-cache.js`:FIGMA_CACHE_PROJECT_CONFIG
|
|
9
|
+
* 加载顺序见 `figma-cache/figma-cache.js`:FIGMA_CACHE_PROJECT_CONFIG -> figma-cache.config.js -> .figmacacherc.js
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const fs = require("fs");
|
|
@@ -45,6 +45,21 @@ const ADAPTER_DOC_CACHE_REL =
|
|
|
45
45
|
const ADAPTER_DOC_WRITE_POLICY =
|
|
46
46
|
process.env.FIGMA_CACHE_ADAPTER_DOC_WRITE_POLICY || "if-missing";
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* 全局 UI adapter contract 目标路径(相对项目根)。
|
|
50
|
+
* 该 contract 作为「设计 token/state -> 项目实现」的单一真源。
|
|
51
|
+
*/
|
|
52
|
+
const ADAPTER_CONTRACT_REL =
|
|
53
|
+
process.env.FIGMA_CACHE_ADAPTER_CONTRACT ||
|
|
54
|
+
"figma-cache/adapters/ui-adapter.contract.json";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* contract 模板来源(相对项目根,通常来自 cursor-bootstrap)。
|
|
58
|
+
*/
|
|
59
|
+
const ADAPTER_CONTRACT_TEMPLATE_REL =
|
|
60
|
+
process.env.FIGMA_CACHE_ADAPTER_CONTRACT_TEMPLATE ||
|
|
61
|
+
"cursor-bootstrap/examples/ui-adapter.contract.template.json";
|
|
62
|
+
|
|
48
63
|
/**
|
|
49
64
|
* 人类可读的「流程 / 需求总览」骨架路径(相对项目根)。仅本示例写入;可在业务项目中改路径或删除相关逻辑。
|
|
50
65
|
* @type {string}
|
|
@@ -99,13 +114,14 @@ function writeTextByPolicy(absPath, content) {
|
|
|
99
114
|
* @returns {string}
|
|
100
115
|
*/
|
|
101
116
|
function buildCacheRootHint(ctx) {
|
|
102
|
-
return `# Figma 缓存
|
|
117
|
+
return `# Figma 缓存 -> UI 实现(目录级提示)
|
|
103
118
|
|
|
104
119
|
本文件由示例 \`postEnsure\` 生成,默认放在 **figma-cache 目录级**,用于避免“每个节点重复生成同一提示”。
|
|
105
120
|
|
|
106
121
|
- **默认来源优先级**:先用 \`raw.json\` / \`spec.md\` / \`meta.json\` / \`state-map.md\`,仅在缺口或冲突时再读 \`mcp-raw/*\`
|
|
107
122
|
- **证据约束**:同一设计事实只保留一个主证据来源,避免重复引用
|
|
108
123
|
- **命中检查**:先查本地缓存命中与字段覆盖,再决定是否需要 MCP 补齐
|
|
124
|
+
- **全局映射契约**:先读取 \`${ADAPTER_CONTRACT_REL}\`,将 token/state 映射到项目实现;未映射项禁止猜测
|
|
109
125
|
|
|
110
126
|
可选模式(环境变量):
|
|
111
127
|
- \`FIGMA_CACHE_ADAPTER_DOC_MODE=cache-root\`(默认)
|
|
@@ -122,7 +138,7 @@ function buildCacheRootHint(ctx) {
|
|
|
122
138
|
*/
|
|
123
139
|
function buildNodeHint(ctx) {
|
|
124
140
|
const nodeLabel = ctx.nodeId == null ? "" : String(ctx.nodeId);
|
|
125
|
-
return `# Figma 缓存
|
|
141
|
+
return `# Figma 缓存 -> UI 实现(节点提示)
|
|
126
142
|
|
|
127
143
|
本文件由示例 \`postEnsure\` 生成。若你希望减少重复,可改用目录级模式:\`FIGMA_CACHE_ADAPTER_DOC_MODE=cache-root\`。
|
|
128
144
|
|
|
@@ -130,6 +146,7 @@ function buildNodeHint(ctx) {
|
|
|
130
146
|
- cacheKey: \`${ctx.cacheKey}\`
|
|
131
147
|
- fileKey: \`${ctx.fileKey}\`
|
|
132
148
|
- nodeId: \`${nodeLabel}\`
|
|
149
|
+
- 全局映射契约:\`${ADAPTER_CONTRACT_REL}\`
|
|
133
150
|
|
|
134
151
|
**流程 / 交互总览(可选)**:若使用本示例默认钩子,项目根下另有 **\`${FLOW_README_REL}\`**,随每次 \`ensure\` 追加节点小节,便于与 \`index.json\` 里的 \`flows\` 互补(人读 md,机读索引)。
|
|
135
152
|
`;
|
|
@@ -155,6 +172,26 @@ function writeAdapterHint(ctx) {
|
|
|
155
172
|
writeTextByPolicy(cacheRootTarget, buildCacheRootHint(ctx));
|
|
156
173
|
}
|
|
157
174
|
|
|
175
|
+
/**
|
|
176
|
+
* 保证项目存在全局 adapter contract(单一真源)。
|
|
177
|
+
* 默认仅在缺失时写入,避免覆盖项目已定制内容。
|
|
178
|
+
* @param {object} ctx
|
|
179
|
+
*/
|
|
180
|
+
function ensureAdapterContract(ctx) {
|
|
181
|
+
const targetAbs = path.resolve(ctx.root, ADAPTER_CONTRACT_REL);
|
|
182
|
+
if (fs.existsSync(targetAbs)) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const templateAbs = path.resolve(ctx.root, ADAPTER_CONTRACT_TEMPLATE_REL);
|
|
187
|
+
if (!fs.existsSync(templateAbs)) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fs.mkdirSync(path.dirname(targetAbs), { recursive: true });
|
|
192
|
+
fs.copyFileSync(templateAbs, targetAbs);
|
|
193
|
+
}
|
|
194
|
+
|
|
158
195
|
/**
|
|
159
196
|
* 在单文件里维护「已缓存节点」登记(按 cacheKey 幂等追加),与 index.json / flows 互补:适合评审与新人阅读。
|
|
160
197
|
* @param {object} ctx
|
|
@@ -164,13 +201,13 @@ function appendFlowReadmeRegistry(ctx) {
|
|
|
164
201
|
const marker = `<!-- cache-node:${ctx.cacheKey} -->`;
|
|
165
202
|
const specRel = normalizePosixPath(path.relative(ctx.root, path.resolve(ctx.root, ctx.paths.spec)));
|
|
166
203
|
const metaRel = normalizePosixPath(path.relative(ctx.root, path.resolve(ctx.root, ctx.paths.meta)));
|
|
167
|
-
const completeness = Array.isArray(ctx.completeness) && ctx.completeness.length ? ctx.completeness.join(", ") : "
|
|
204
|
+
const completeness = Array.isArray(ctx.completeness) && ctx.completeness.length ? ctx.completeness.join(", ") : "-";
|
|
168
205
|
const block =
|
|
169
206
|
`\n${marker}\n` +
|
|
170
207
|
`### \`${ctx.cacheKey}\`\n\n` +
|
|
171
|
-
`- **Figma**: ${ctx.url || "
|
|
172
|
-
`- **syncedAt**: ${ctx.syncedAt || "
|
|
173
|
-
`- **source**: ${ctx.source || "
|
|
208
|
+
`- **Figma**: ${ctx.url || "-"}\n` +
|
|
209
|
+
`- **syncedAt**: ${ctx.syncedAt || "-"}\n` +
|
|
210
|
+
`- **source**: ${ctx.source || "-"}\n` +
|
|
174
211
|
`- **completeness**: ${completeness}\n` +
|
|
175
212
|
`- **spec**: \`${specRel}\` · **meta**: \`${metaRel}\`\n` +
|
|
176
213
|
`- **提示**: 像素级还原以 \`spec.md\` / \`raw.json\` 为准;用户路径请维护 \`flows\` 后把 \`npm run figma:cache:flow mermaid\` 输出贴到下方「流程总览」。\n`;
|
|
@@ -219,16 +256,21 @@ module.exports = {
|
|
|
219
256
|
ADAPTER_DOC_MODE,
|
|
220
257
|
ADAPTER_DOC_CACHE_REL,
|
|
221
258
|
ADAPTER_DOC_WRITE_POLICY,
|
|
259
|
+
ADAPTER_CONTRACT_REL,
|
|
260
|
+
ADAPTER_CONTRACT_TEMPLATE_REL,
|
|
222
261
|
FLOW_README_REL,
|
|
223
262
|
appendFlowReadmeRegistry,
|
|
263
|
+
ensureAdapterContract,
|
|
224
264
|
|
|
225
265
|
hooks: {
|
|
226
266
|
/**
|
|
227
|
-
* 默认实现:目录级 adapter 提示(避免节点重复)+
|
|
267
|
+
* 默认实现:目录级 adapter 提示(避免节点重复)+ 全局 adapter contract(缺失时自动落地)
|
|
268
|
+
* + 项目根下「流程/需求」总览骨架(单文件、幂等追加节点块)。
|
|
228
269
|
* 用 Agent 生成业务方案后,可整体替换本模块逻辑。
|
|
229
270
|
*/
|
|
230
271
|
postEnsure(ctx) {
|
|
231
272
|
try {
|
|
273
|
+
ensureAdapterContract(ctx);
|
|
232
274
|
writeAdapterHint(ctx);
|
|
233
275
|
appendFlowReadmeRegistry(ctx);
|
|
234
276
|
} catch (err) {
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"managedFiles": [
|
|
3
|
-
{
|
|
4
|
-
"from": "rules/00-output-token-budget.mdc",
|
|
5
|
-
"to": ".cursor/rules/00-output-token-budget.mdc"
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"from": "rules/01-figma-cache-core.mdc",
|
|
9
|
-
"to": ".cursor/rules/01-figma-cache-core.mdc"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"from": "rules/02-figma-stack-adapter.mdc",
|
|
13
|
-
"to": ".cursor/rules/02-figma-stack-adapter.mdc"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"from": "rules/03-figma-ui-implementation-hard-constraints.mdc",
|
|
17
|
-
"to": ".cursor/rules/03-figma-ui-implementation-hard-constraints.mdc"
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"from": "rules/04-ui-baseline-governance.mdc",
|
|
21
|
-
"to": ".cursor/rules/04-ui-baseline-governance.mdc"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"from": "rules/figma-local-cache-first.mdc",
|
|
25
|
-
"to": ".cursor/rules/figma-local-cache-first.mdc"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"from": "skills/figma-mcp-local-cache/SKILL.md",
|
|
29
|
-
"to": ".cursor/skills/figma-mcp-local-cache/SKILL.md"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"from": "skills/figma-ui-dual-mode-execution/SKILL.md",
|
|
33
|
-
"to": ".cursor/skills/figma-ui-dual-mode-execution/SKILL.md"
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
|
-
"retiredFiles": [
|
|
37
|
-
".cursor/skills/ui-baseline-governance/SKILL.md",
|
|
38
|
-
".cursor/rules/04-command-execution-anti-regression.mdc",
|
|
39
|
-
".cursor/rules/commit-conventions.mdc"
|
|
40
|
-
]
|
|
1
|
+
{
|
|
2
|
+
"managedFiles": [
|
|
3
|
+
{
|
|
4
|
+
"from": "rules/00-output-token-budget.mdc",
|
|
5
|
+
"to": ".cursor/rules/00-output-token-budget.mdc"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"from": "rules/01-figma-cache-core.mdc",
|
|
9
|
+
"to": ".cursor/rules/01-figma-cache-core.mdc"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"from": "rules/02-figma-stack-adapter.mdc",
|
|
13
|
+
"to": ".cursor/rules/02-figma-stack-adapter.mdc"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"from": "rules/03-figma-ui-implementation-hard-constraints.mdc",
|
|
17
|
+
"to": ".cursor/rules/03-figma-ui-implementation-hard-constraints.mdc"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"from": "rules/04-ui-baseline-governance.mdc",
|
|
21
|
+
"to": ".cursor/rules/04-ui-baseline-governance.mdc"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"from": "rules/figma-local-cache-first.mdc",
|
|
25
|
+
"to": ".cursor/rules/figma-local-cache-first.mdc"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"from": "skills/figma-mcp-local-cache/SKILL.md",
|
|
29
|
+
"to": ".cursor/skills/figma-mcp-local-cache/SKILL.md"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"from": "skills/figma-ui-dual-mode-execution/SKILL.md",
|
|
33
|
+
"to": ".cursor/skills/figma-ui-dual-mode-execution/SKILL.md"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"retiredFiles": [
|
|
37
|
+
".cursor/skills/ui-baseline-governance/SKILL.md",
|
|
38
|
+
".cursor/rules/04-command-execution-anti-regression.mdc",
|
|
39
|
+
".cursor/rules/commit-conventions.mdc"
|
|
40
|
+
]
|
|
41
41
|
}
|
|
@@ -1,37 +1,55 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: figma-ui-dual-mode-execution
|
|
3
|
-
description: 仅用 nodeId
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Figma UI Dual Mode Execution
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
- `
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
---
|
|
2
|
+
name: figma-ui-dual-mode-execution
|
|
3
|
+
description: 仅用 nodeId(如 9277-28772)或 Figma 链接触发 UI 实现,自动在短流程与严格流程间切换。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Figma UI Dual Mode Execution
|
|
7
|
+
|
|
8
|
+
本 Skill 用于:用户仅提供节点线索(节点目录名、nodeId、或带 node-id 的 Figma 链接)时,自动完成“定位缓存 -> 判定模式 -> 实现与验证”。
|
|
9
|
+
|
|
10
|
+
## 支持输入
|
|
11
|
+
|
|
12
|
+
- 节点目录名:如 `9277-28772`
|
|
13
|
+
- nodeId:如 `9277:28772`
|
|
14
|
+
- Figma 链接:`...node-id=9277-28772`(需转换为 `9277:28772`)
|
|
15
|
+
|
|
16
|
+
## 执行步骤(强制)
|
|
17
|
+
|
|
18
|
+
1. 规范化节点标识:
|
|
19
|
+
- `9277-28772` -> `9277:28772`
|
|
20
|
+
2. 在 `figma-cache/index.json` 查命中并定位节点目录。
|
|
21
|
+
3. 读取四份必读文件:
|
|
22
|
+
- `spec.md`
|
|
23
|
+
- `raw.json`
|
|
24
|
+
- `state-map.md`
|
|
25
|
+
- `mcp-raw-get-design-context.txt`
|
|
26
|
+
4. 读取全局 adapter contract(新增强制项):
|
|
27
|
+
- 默认路径:`figma-cache/adapters/ui-adapter.contract.json`
|
|
28
|
+
- 目标:把 token/state 从设计事实映射到项目实现(变量/class/主题 token)
|
|
29
|
+
5. 模式选择:
|
|
30
|
+
- 默认短流程;
|
|
31
|
+
- 命中任一升级条件(老项目/全局样式改动/复杂状态/历史漂移问题/信息冲突)-> 切严格流程。
|
|
32
|
+
6. 预检文档策略(降噪):
|
|
33
|
+
- 默认短流程:可跳过完整预检文档,仅输出精简事实清单。
|
|
34
|
+
- 严格流程:必须基于 `cursor-bootstrap/examples/ui-1to1-preflight.template.md` 生成并填写“预检文档”(可落到项目 `figma-cache/docs/` 或节点目录旁),至少完成:设计值快照、状态对照表、1:1 预检清单。
|
|
35
|
+
7. 先输出“事实对齐清单”,再实现组件与挂载。
|
|
36
|
+
8. 改动后执行 lint,并输出映射与验证结论。
|
|
37
|
+
|
|
38
|
+
## 关键硬约束
|
|
39
|
+
|
|
40
|
+
- 冲突裁决顺序:`mcp-raw-get-design-context.txt` 优先。
|
|
41
|
+
- 禁止猜测设计值;无法裁决必须先提问。
|
|
42
|
+
- 对 token/state 未命中 adapter contract 的项,必须先补 mapping 或向用户确认,禁止凭经验填色。
|
|
43
|
+
- 禁止使用 Figma 临时远程资产 URL 作为运行时图标。
|
|
44
|
+
- 图标优先项目图标系统;无则 `inline svg`。
|
|
45
|
+
- 默认按 `border-box` 思维实现;弹层必须锚定触发器。
|
|
46
|
+
|
|
47
|
+
## 固定输出
|
|
48
|
+
|
|
49
|
+
1. 缓存定位结果(命中节点目录)
|
|
50
|
+
2. 事实对齐清单(结构/文案/token/状态/交互)
|
|
51
|
+
3. adapter contract 命中结果(命中项 / 缺失项)
|
|
52
|
+
4. 变更文件列表
|
|
53
|
+
5. 关键设计值 -> 代码映射
|
|
54
|
+
6. lint/验证结果
|
|
55
|
+
7. 未决问题(如有)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "button",
|
|
3
|
+
"description": "Generic clickable button recipe",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"button-shell",
|
|
6
|
+
"label",
|
|
7
|
+
"leading-icon",
|
|
8
|
+
"trailing-icon"
|
|
9
|
+
],
|
|
10
|
+
"stateMachine": {
|
|
11
|
+
"requiredStates": ["default", "hover", "active", "disabled"],
|
|
12
|
+
"optionalStates": ["loading", "focus-visible"]
|
|
13
|
+
},
|
|
14
|
+
"tokenPriority": [
|
|
15
|
+
"background",
|
|
16
|
+
"text",
|
|
17
|
+
"icon",
|
|
18
|
+
"border"
|
|
19
|
+
],
|
|
20
|
+
"pitfalls": [
|
|
21
|
+
"Do not lose disabled contrast",
|
|
22
|
+
"Do not collapse hover and active states"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "card",
|
|
3
|
+
"description": "Generic card recipe for content containers",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"card-shell",
|
|
6
|
+
"header",
|
|
7
|
+
"body",
|
|
8
|
+
"footer"
|
|
9
|
+
],
|
|
10
|
+
"stateMachine": {
|
|
11
|
+
"requiredStates": ["default"],
|
|
12
|
+
"optionalStates": ["hover", "selected", "disabled"]
|
|
13
|
+
},
|
|
14
|
+
"tokenPriority": [
|
|
15
|
+
"surface",
|
|
16
|
+
"border",
|
|
17
|
+
"title-text",
|
|
18
|
+
"body-text"
|
|
19
|
+
],
|
|
20
|
+
"pitfalls": [
|
|
21
|
+
"Do not remove spacing hierarchy between header/body/footer",
|
|
22
|
+
"Do not flatten card elevation when hover state exists"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "checkbox",
|
|
3
|
+
"description": "Generic checkbox recipe for multi-select controls",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"control",
|
|
6
|
+
"check-indicator",
|
|
7
|
+
"label",
|
|
8
|
+
"helper-text"
|
|
9
|
+
],
|
|
10
|
+
"stateMachine": {
|
|
11
|
+
"requiredStates": ["unchecked", "checked", "disabled"],
|
|
12
|
+
"optionalStates": ["indeterminate", "error"]
|
|
13
|
+
},
|
|
14
|
+
"tokenPriority": [
|
|
15
|
+
"control-bg",
|
|
16
|
+
"control-border",
|
|
17
|
+
"icon",
|
|
18
|
+
"label-text"
|
|
19
|
+
],
|
|
20
|
+
"pitfalls": [
|
|
21
|
+
"Do not skip indeterminate style if design includes partial selection",
|
|
22
|
+
"Do not hide disabled state contrast"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "input",
|
|
3
|
+
"description": "Generic text-input recipe for form controls",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"label",
|
|
6
|
+
"input-shell",
|
|
7
|
+
"prefix-or-suffix",
|
|
8
|
+
"helper-text"
|
|
9
|
+
],
|
|
10
|
+
"stateMachine": {
|
|
11
|
+
"requiredStates": ["default", "focused", "error", "disabled"],
|
|
12
|
+
"optionalStates": ["readonly", "success"]
|
|
13
|
+
},
|
|
14
|
+
"tokenPriority": [
|
|
15
|
+
"border",
|
|
16
|
+
"text",
|
|
17
|
+
"placeholder",
|
|
18
|
+
"background"
|
|
19
|
+
],
|
|
20
|
+
"pitfalls": [
|
|
21
|
+
"Do not merge error state into default style",
|
|
22
|
+
"Do not ignore focused outline or border token"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "modal",
|
|
3
|
+
"description": "Generic modal/dialog recipe for overlay interactions",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"overlay",
|
|
6
|
+
"container",
|
|
7
|
+
"header",
|
|
8
|
+
"content",
|
|
9
|
+
"actions"
|
|
10
|
+
],
|
|
11
|
+
"stateMachine": {
|
|
12
|
+
"requiredStates": ["closed", "open"],
|
|
13
|
+
"optionalStates": ["loading", "confirming"]
|
|
14
|
+
},
|
|
15
|
+
"tokenPriority": [
|
|
16
|
+
"overlay",
|
|
17
|
+
"surface",
|
|
18
|
+
"text",
|
|
19
|
+
"action"
|
|
20
|
+
],
|
|
21
|
+
"pitfalls": [
|
|
22
|
+
"Do not remove overlay semantics when modal opens",
|
|
23
|
+
"Do not skip action button hierarchy in footer"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "radio",
|
|
3
|
+
"description": "Generic radio recipe for single-select controls",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"control",
|
|
6
|
+
"dot-indicator",
|
|
7
|
+
"label"
|
|
8
|
+
],
|
|
9
|
+
"stateMachine": {
|
|
10
|
+
"requiredStates": ["unselected", "selected", "disabled"],
|
|
11
|
+
"optionalStates": ["error"]
|
|
12
|
+
},
|
|
13
|
+
"tokenPriority": [
|
|
14
|
+
"control-border",
|
|
15
|
+
"control-fill",
|
|
16
|
+
"dot",
|
|
17
|
+
"label-text"
|
|
18
|
+
],
|
|
19
|
+
"pitfalls": [
|
|
20
|
+
"Do not mix selected/unselected semantics",
|
|
21
|
+
"Do not remove keyboard focus style"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "select",
|
|
3
|
+
"description": "Generic select/dropdown recipe for UI generation",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"trigger",
|
|
6
|
+
"panel",
|
|
7
|
+
"option",
|
|
8
|
+
"selected-indicator"
|
|
9
|
+
],
|
|
10
|
+
"stateMachine": {
|
|
11
|
+
"requiredStates": ["default", "expanded", "selected", "unselected"],
|
|
12
|
+
"optionalStates": ["disabled", "loading"]
|
|
13
|
+
},
|
|
14
|
+
"tokenPriority": [
|
|
15
|
+
"background",
|
|
16
|
+
"text",
|
|
17
|
+
"icon",
|
|
18
|
+
"border"
|
|
19
|
+
],
|
|
20
|
+
"pitfalls": [
|
|
21
|
+
"Do not hardcode selected style without state linkage",
|
|
22
|
+
"Do not drop unselected state when selected exists"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "table",
|
|
3
|
+
"description": "Generic data-table recipe for tabular views",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"table-shell",
|
|
6
|
+
"header-row",
|
|
7
|
+
"body-rows",
|
|
8
|
+
"empty-state",
|
|
9
|
+
"pagination"
|
|
10
|
+
],
|
|
11
|
+
"stateMachine": {
|
|
12
|
+
"requiredStates": ["default", "row-hover", "row-selected"],
|
|
13
|
+
"optionalStates": ["loading", "empty", "error"]
|
|
14
|
+
},
|
|
15
|
+
"tokenPriority": [
|
|
16
|
+
"header",
|
|
17
|
+
"row-bg",
|
|
18
|
+
"row-text",
|
|
19
|
+
"divider"
|
|
20
|
+
],
|
|
21
|
+
"pitfalls": [
|
|
22
|
+
"Do not collapse row-selected and row-hover style",
|
|
23
|
+
"Do not remove empty-state when data is unavailable"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tabs",
|
|
3
|
+
"description": "Generic tabs recipe for segmented navigation",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"tab-list",
|
|
6
|
+
"tab-item",
|
|
7
|
+
"active-indicator",
|
|
8
|
+
"tab-panel"
|
|
9
|
+
],
|
|
10
|
+
"stateMachine": {
|
|
11
|
+
"requiredStates": ["default", "active"],
|
|
12
|
+
"optionalStates": ["hover", "disabled"]
|
|
13
|
+
},
|
|
14
|
+
"tokenPriority": [
|
|
15
|
+
"active-text",
|
|
16
|
+
"inactive-text",
|
|
17
|
+
"indicator",
|
|
18
|
+
"panel-bg"
|
|
19
|
+
],
|
|
20
|
+
"pitfalls": [
|
|
21
|
+
"Do not render tab-panel without matching active tab state",
|
|
22
|
+
"Do not drop active indicator for selected tab"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tooltip",
|
|
3
|
+
"description": "Generic tooltip recipe for contextual hints",
|
|
4
|
+
"structureTemplate": [
|
|
5
|
+
"trigger",
|
|
6
|
+
"bubble",
|
|
7
|
+
"arrow",
|
|
8
|
+
"content"
|
|
9
|
+
],
|
|
10
|
+
"stateMachine": {
|
|
11
|
+
"requiredStates": ["hidden", "visible"],
|
|
12
|
+
"optionalStates": ["delayed", "pinned"]
|
|
13
|
+
},
|
|
14
|
+
"tokenPriority": [
|
|
15
|
+
"bubble-bg",
|
|
16
|
+
"text",
|
|
17
|
+
"shadow",
|
|
18
|
+
"arrow"
|
|
19
|
+
],
|
|
20
|
+
"pitfalls": [
|
|
21
|
+
"Do not show tooltip persistently in hidden state",
|
|
22
|
+
"Do not detach arrow color from bubble color"
|
|
23
|
+
]
|
|
24
|
+
}
|