Skip to content

Commit 0042ecf

Browse files
committed
feat(tokens): 补 pill 圆角档并改判漂移断言
1 parent 2ebac5e commit 0042ecf

5 files changed

Lines changed: 36 additions & 4 deletions

File tree

‎app/scripts/gen-tokens.mjs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,19 @@ export const SCALE_SOURCE = {
116116
typeScale: TYPE_SCALE.map((t) => `${t.size}px/${t.line}px·${t.weight}`),
117117
/** 间距:4 为半档,其余落 8px 网格 */
118118
spaceScale: [4, 8, 12, 16, 24, 32, 48],
119-
/** 圆角:3 印章 · 5 控件与卡 · 8 面板 · 10 浮层 */
119+
/**
120+
* 圆角:3 印章 · 5 控件与卡 · 8 面板 · 10 浮层 · 999 药丸(批 4 B17 的第 5 档;规格 §4.2 只写四档)。
121+
*
122+
* `pill` 的 999 **不是本任务自创的数字**:它是原语层 `ui/primitives/Surface.css:58` 里既有的兜底值
123+
* `var(--ed-radius-pill, 999px)`(全仓唯一命中,R2.3「取既有原语层兜底值」)。批 6 T5 把它升为
124+
* 真源档位后,真源与唯一消费者同值 —— 由 `gen-tokens.test.mjs` 的「== 原语层兜底值」对拍钉住。
125+
*/
120126
radiusScale: [
121127
{ name: "stamp", px: 3 },
122128
{ name: "control", px: 5 },
123129
{ name: "panel", px: 8 },
124130
{ name: "overlay", px: 10 },
131+
{ name: "pill", px: 999 },
125132
],
126133
/** 遮罩透明度(配 overlay 基色) */
127134
overlayAlpha: 0.34,

‎app/scripts/gen-tokens.test.mjs‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@
1010
* 其产物 src/note-mark.css 目前**无漂移守卫** —— 已登记于批 0-A 计划「交接给 0-B/0-C/0-D 的硬前置」,
1111
* 待并入或显式豁免。
1212
*/
13+
import { readFileSync } from "node:fs";
14+
import { dirname, join } from "node:path";
15+
import { fileURLToPath } from "node:url";
1316
import { describe, expect, it } from "vitest";
1417
import { COLOR_TOKENS, CONTRAST_BASELINE, SCALE_SOURCE, SHADOW_TOKENS, TYPE_SCALE, renderAll } from "./gen-tokens.mjs";
1518
import { contrastRatio } from "../src/ui/contrast.ts";
1619

20+
/** 生成器所在目录(批 6 T5 起:`pill` 档要与原语层 `Surface.css` 的兜底值对拍,需要读文件) */
21+
const HERE = dirname(fileURLToPath(import.meta.url));
22+
1723
describe("gen-tokens 规范数据", () => {
1824
it("每个 token 名唯一", () => {
1925
const names = COLOR_TOKENS.map((t) => t.name);
@@ -111,10 +117,25 @@ describe("renderAll", () => {
111117
expect(SCALE_SOURCE.fontFamilyBody).toContain("Source Han Serif SC");
112118
expect(SCALE_SOURCE.fontFamilyMono).toContain("JetBrains Mono");
113119
expect(SCALE_SOURCE.spaceScale).toEqual([4, 8, 12, 16, 24, 32, 48]);
114-
expect(SCALE_SOURCE.radiusScale.map((r) => r.px)).toEqual([3, 5, 8, 10]);
120+
// 批 6 T5(R2.3/G14):第 5 档 `pill` = 999 —— 与 `src/ui/tokens.drift.test.ts:52` 是**两处独立
121+
// 真源断言**(R11.8 第 5 条),凡改 `radiusScale` 必须同时处理两处。
122+
expect(SCALE_SOURCE.radiusScale.map((r) => r.px)).toEqual([3, 5, 8, 10, 999]);
115123
expect(SCALE_SOURCE.typeScale.length).toBeGreaterThanOrEqual(6);
116124
});
117125

126+
/**
127+
* `pill` 的唯一消费者是原语层 `Surface.css`(它今天写 `var(--ed-radius-pill, 999px)` 兜底)。
128+
* 本条把**真源值**与**消费者兜底字面量**对拍:任一侧单独改动都会红 —— 若只改真源,兜底值就变成
129+
* 一个「与真源不同的死数字」(未定义变量不报错,会静默退回 999);若只改兜底,真源就不再是权威。
130+
* 仪器自带防真空:兜底字面量抓不到 ⇒ `undefined` ⇒ 第 1 条断言红;`pill` 档丢失 ⇒ `undefined` ≠ 数字 ⇒ 红。
131+
*/
132+
it("`pill` 档的 px 等于原语层唯一的兜底字面量(真源 ↔ 消费者同值)", () => {
133+
const surface = readFileSync(join(HERE, "..", "src", "ui", "primitives", "Surface.css"), "utf8");
134+
const fallback = /var\(--ed-radius-pill,\s*(\d+)px\)/.exec(surface)?.[1];
135+
expect(fallback, "Surface.css 缺 `var(--ed-radius-pill, <n>px)` —— 唯一消费者被改?").toBeDefined();
136+
expect(SCALE_SOURCE.radiusScale.find((r) => r.name === "pill")?.px, "pill 真源值 ≠ 原语层兜底值").toBe(Number(fallback));
137+
});
138+
118139
// 规范 §4.2 字阶逐字为「25/600 · 17/600 · 15.5/1.9 · 13/20 · 12/18 · 11.5/16 mono(下界 12px)」:
119140
// 11.5/16 mono 是被**点名**的档位(等宽,用于时间码/元数据),括注的 12px 下界约束其余档。
120141
// 故硬下界钉在 11.5:既守住「消灭 10px/11px」,又不把 mono 档私下抬到 12px

‎app/src/ui/tokens.css‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
--ed-radius-control: 5px;
6262
--ed-radius-panel: 8px;
6363
--ed-radius-overlay: 10px;
64+
--ed-radius-pill: 999px;
6465

6566
/* 阴影(规范 §4.2②):亮档投影;暗档在 [data-theme="dark"] 里改为反相白描边 */
6667
--ed-shadow-1: 0 1px 2px rgba(28,25,23,.06), 0 4px 12px rgba(28,25,23,.08); /* 低层:菜单 / 浮层 / 小卡(亮档投影;暗档反相描边) */

‎app/src/ui/tokens.drift.test.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ describe("token 门面一致性", () => {
4949

5050
it("SCALE_TOKENS 的间距与圆角与规范一致", () => {
5151
expect([...SCALE_TOKENS.spaceScale]).toEqual([4, 8, 12, 16, 24, 32, 48]);
52-
expect(SCALE_TOKENS.radiusScale.map((r) => r.px)).toEqual([3, 5, 8, 10]);
52+
// 第 5 档 `pill` 是批 4 B17 的药丸档(规格 §4.2 只写四档);**999 取自原语层既有兜底值**
53+
// `Surface.css:58` 的 `var(--ed-radius-pill, 999px)`,不是自创数字(批 6 R2.3 / R11.8 第 2 条)。
54+
// 真源侧(生成器 `SCALE_SOURCE`)的同值断言在 `scripts/gen-tokens.test.mjs` —— 两处独立、必须同时改。
55+
expect(SCALE_TOKENS.radiusScale.map((r) => r.px)).toEqual([3, 5, 8, 10, 999]);
5356
});
5457

5558
// 生成器只持有数据、不含任何 WCAG 计算;此处用 Task 2 的权威实现校验这份数据。

‎app/src/ui/tokens.gen.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const SCALE_TOKENS = {
4949
typeScale: ["25px/34px·600","17px/24px·600","15.5px/29.5px·400","13px/20px·400","12px/18px·500","11.5px/16px·500"],
5050
typeScaleVars: [{"size":25,"line":34,"weight":600},{"size":17,"line":24,"weight":600},{"size":15.5,"line":29.5,"weight":400},{"size":13,"line":20,"weight":400},{"size":12,"line":18,"weight":500},{"size":11.5,"line":16,"weight":500}],
5151
spaceScale: [4,8,12,16,24,32,48],
52-
radiusScale: [{"name":"stamp","px":3},{"name":"control","px":5},{"name":"panel","px":8},{"name":"overlay","px":10}],
52+
radiusScale: [{"name":"stamp","px":3},{"name":"control","px":5},{"name":"panel","px":8},{"name":"overlay","px":10},{"name":"pill","px":999}],
5353
overlayAlpha: 0.34,
5454
iconGrid: 24,
5555
iconStroke: 1.75,

0 commit comments

Comments
 (0)