@qw-ui/tokens 0.3.0-next.40 → 0.3.0-next.42
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 +20 -56
- package/dist/color-architecture.d.ts +28 -4
- package/dist/derive/index.d.ts +1 -1
- package/dist/derive/reference.d.ts +12 -1
- package/dist/derive/semantic.d.ts +7 -0
- package/dist/index.js +389 -247
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css +6 -0
- package/dist/tokens.css +52 -1
- package/dist/tokens.json +96 -2
- package/dist/tokens.live.css +52 -1
- package/dist/tokens.ts +101 -7
- package/package.json +11 -29
package/dist/index.js
CHANGED
|
@@ -474,6 +474,13 @@ const T2_OKLCH_STEPS = [
|
|
|
474
474
|
800,
|
|
475
475
|
900
|
|
476
476
|
];
|
|
477
|
+
/** RFC0012 approved local standard endpoint; Figma synchronization is pending. */
|
|
478
|
+
const T2_BLACK_CONTRAST_ENDPOINT = {
|
|
479
|
+
step: "contrast-endpoint",
|
|
480
|
+
value: "#000000",
|
|
481
|
+
source: "CSS Color sRGB black mathematical endpoint; specs/rfcs/0012-brand-solid-text-contrast.md",
|
|
482
|
+
rationale: "The zero sRGB endpoint is a standard constant for on-brand AA text, independent of Seed and existing color scales."
|
|
483
|
+
};
|
|
477
484
|
const FIGMA_T2_SOLID_SCALE = {
|
|
478
485
|
brand: {
|
|
479
486
|
50: "#F2F6FF",
|
|
@@ -621,8 +628,9 @@ const FIGMA_T2_SOLID_SCALE = {
|
|
|
621
628
|
}
|
|
622
629
|
};
|
|
623
630
|
/**
|
|
624
|
-
* Figma「Color Token System
|
|
625
|
-
*
|
|
631
|
+
* Figma「Color Token System」既有角色及用户批准的本地补充角色。
|
|
632
|
+
* 既有角色与 Figma 节点 22258:49986 对齐;新角色等待 Figma 同步,不冒充已回流。
|
|
633
|
+
* light/dark 均引用 T2;`effect.shadow.*.color` 为复合阴影的颜色
|
|
626
634
|
* 分量(对应 Figma 变量 `--qw-sem-effect-shadow-*-color`)。
|
|
627
635
|
*/
|
|
628
636
|
const FIGMA_T3_COLOR_ROLES = {
|
|
@@ -666,6 +674,10 @@ const FIGMA_T3_COLOR_ROLES = {
|
|
|
666
674
|
light: "color.gray.50",
|
|
667
675
|
dark: "color.black.900"
|
|
668
676
|
},
|
|
677
|
+
"content.danger": {
|
|
678
|
+
light: "color.red.600",
|
|
679
|
+
dark: "color.red.300"
|
|
680
|
+
},
|
|
669
681
|
"content.primary": {
|
|
670
682
|
light: "color.black.base",
|
|
671
683
|
dark: "color.white.base"
|
|
@@ -706,6 +718,10 @@ const FIGMA_T3_COLOR_ROLES = {
|
|
|
706
718
|
light: "color.white.base",
|
|
707
719
|
dark: "color.white.base"
|
|
708
720
|
},
|
|
721
|
+
"content.on-brand": {
|
|
722
|
+
light: "color.white.base",
|
|
723
|
+
dark: "color.black.contrast-endpoint"
|
|
724
|
+
},
|
|
709
725
|
"content.on-warning-subtle": {
|
|
710
726
|
light: "color.yellow.800",
|
|
711
727
|
dark: "color.yellow.200"
|
|
@@ -718,6 +734,10 @@ const FIGMA_T3_COLOR_ROLES = {
|
|
|
718
734
|
light: "color.gray.300",
|
|
719
735
|
dark: "color.gray.600"
|
|
720
736
|
},
|
|
737
|
+
"border.control": {
|
|
738
|
+
light: "color.gray.600",
|
|
739
|
+
dark: "color.gray.base"
|
|
740
|
+
},
|
|
721
741
|
"border.focus": {
|
|
722
742
|
light: "color.brand.base",
|
|
723
743
|
dark: "color.brand.500"
|
|
@@ -779,8 +799,8 @@ const FIGMA_T3_COLOR_ROLES = {
|
|
|
779
799
|
dark: "color.blue.a20"
|
|
780
800
|
},
|
|
781
801
|
"control-action.danger.default": {
|
|
782
|
-
light: "color.red.
|
|
783
|
-
dark: "color.red.
|
|
802
|
+
light: "color.red.600",
|
|
803
|
+
dark: "color.red.600"
|
|
784
804
|
},
|
|
785
805
|
"control-action.danger.subtle": {
|
|
786
806
|
light: "color.red.a10",
|
|
@@ -850,6 +870,10 @@ const FIGMA_T3_COLOR_ROLES = {
|
|
|
850
870
|
light: "color.black.a50",
|
|
851
871
|
dark: "color.black.a50"
|
|
852
872
|
},
|
|
873
|
+
"overlay.control-on-media": {
|
|
874
|
+
light: "color.black.a50",
|
|
875
|
+
dark: "color.white.a40"
|
|
876
|
+
},
|
|
853
877
|
shadow: {
|
|
854
878
|
light: "color.black.a10",
|
|
855
879
|
dark: "color.black.a50"
|
|
@@ -1309,6 +1333,7 @@ function evaluateDerivation(d, seed) {
|
|
|
1309
1333
|
case "fontStack": return formatFontFamily(seedValueAt(seed, d.seedRef));
|
|
1310
1334
|
case "cubicBezier": return formatCubicBezier(seedValueAt(seed, d.seedRef));
|
|
1311
1335
|
case "literal": return String(d.value);
|
|
1336
|
+
case "cssEnvironment": return `env(${d.name}, ${d.fallback})`;
|
|
1312
1337
|
case "shadowLayer": {
|
|
1313
1338
|
const { offsetX, offsetY, blur, spread } = shadowShapeOf(seed, d.level);
|
|
1314
1339
|
return `${offsetX} ${offsetY} ${blur} ${spread} ${rgba([
|
|
@@ -1333,7 +1358,8 @@ function seedRefsOf(d) {
|
|
|
1333
1358
|
case "cubicBezier": return [d.seedRef];
|
|
1334
1359
|
case "offsetSteps": return [d.seedRef, d.stepRef];
|
|
1335
1360
|
case "alphaScale": return [d.stepRef];
|
|
1336
|
-
case "literal":
|
|
1361
|
+
case "literal":
|
|
1362
|
+
case "cssEnvironment": return [];
|
|
1337
1363
|
case "shadowLayer": return ["effect.shadow.base", "size.opacity.alphaStep"];
|
|
1338
1364
|
}
|
|
1339
1365
|
}
|
|
@@ -1345,6 +1371,7 @@ function sourceKindOf(d) {
|
|
|
1345
1371
|
case "cubicBezier": return "seed-alias";
|
|
1346
1372
|
case "figmaOklchScale": return "design-calibrated";
|
|
1347
1373
|
case "literal": return "standard-constant";
|
|
1374
|
+
case "cssEnvironment": return "external-standard";
|
|
1348
1375
|
default: return "seed-derived";
|
|
1349
1376
|
}
|
|
1350
1377
|
}
|
|
@@ -1364,6 +1391,7 @@ function formatDerivation(d) {
|
|
|
1364
1391
|
case "seedAlpha": return `= seed.${d.seedRef} / ${round2(d.alpha * 100)}%`;
|
|
1365
1392
|
case "alphaScale": return `= ${d.channel === "black" ? "黑" : "白"} / seed.${d.stepRef} × ${d.multiplier}`;
|
|
1366
1393
|
case "literal": return `= ${d.value}(canonical 标准常量)`;
|
|
1394
|
+
case "cssEnvironment": return `= env(${d.name}, ${d.fallback})(UA external standard)`;
|
|
1367
1395
|
case "shadowLayer": {
|
|
1368
1396
|
const f = SHADOW_LEVELS[d.level];
|
|
1369
1397
|
return `= seed.effect.shadow.base 形状 × {offset ${f.offset}, blur ${f.blur}} · 色 = 黑 / alphaStep × ${f.alphaMult}`;
|
|
@@ -1418,11 +1446,32 @@ function buildColorRampRecipes() {
|
|
|
1418
1446
|
seedRef
|
|
1419
1447
|
}));
|
|
1420
1448
|
}
|
|
1449
|
+
out.push(ref([
|
|
1450
|
+
"color",
|
|
1451
|
+
"black",
|
|
1452
|
+
T2_BLACK_CONTRAST_ENDPOINT.step
|
|
1453
|
+
], {
|
|
1454
|
+
kind: "literal",
|
|
1455
|
+
value: T2_BLACK_CONTRAST_ENDPOINT.value
|
|
1456
|
+
}, {
|
|
1457
|
+
source: T2_BLACK_CONTRAST_ENDPOINT.source,
|
|
1458
|
+
rationale: T2_BLACK_CONTRAST_ENDPOINT.rationale
|
|
1459
|
+
}));
|
|
1421
1460
|
return out;
|
|
1422
1461
|
}
|
|
1423
1462
|
/** 4. 间距刻度 = spacing.step × N (N=1..8)。 */
|
|
1424
1463
|
function buildSpacingRecipes() {
|
|
1425
|
-
const out = [
|
|
1464
|
+
const out = [ref([
|
|
1465
|
+
"size",
|
|
1466
|
+
"spacing",
|
|
1467
|
+
"0"
|
|
1468
|
+
], {
|
|
1469
|
+
kind: "literal",
|
|
1470
|
+
value: "0px"
|
|
1471
|
+
}, {
|
|
1472
|
+
source: "CSS Values zero length",
|
|
1473
|
+
rationale: "A canonical zero needs no theme Seed dependency."
|
|
1474
|
+
})];
|
|
1426
1475
|
for (let n = 1; n <= 8; n++) out.push(ref([
|
|
1427
1476
|
"size",
|
|
1428
1477
|
"spacing",
|
|
@@ -1434,6 +1483,25 @@ function buildSpacingRecipes() {
|
|
|
1434
1483
|
}));
|
|
1435
1484
|
return out;
|
|
1436
1485
|
}
|
|
1486
|
+
function buildSafeAreaInsetRecipes() {
|
|
1487
|
+
return [
|
|
1488
|
+
"top",
|
|
1489
|
+
"right",
|
|
1490
|
+
"bottom",
|
|
1491
|
+
"left"
|
|
1492
|
+
].map((edge) => ref([
|
|
1493
|
+
"size",
|
|
1494
|
+
"safeAreaInset",
|
|
1495
|
+
edge
|
|
1496
|
+
], {
|
|
1497
|
+
kind: "cssEnvironment",
|
|
1498
|
+
name: `safe-area-inset-${edge}`,
|
|
1499
|
+
fallback: "0px"
|
|
1500
|
+
}, {
|
|
1501
|
+
source: "https://www.w3.org/TR/css-env-1/#safe-area-insets",
|
|
1502
|
+
rationale: "Dynamic UA-owned viewport inset; a CSS expression, not a fixed device dimension or Seed input."
|
|
1503
|
+
}));
|
|
1504
|
+
}
|
|
1437
1505
|
/** 圆角档位系数(sm/lg/xl 从 base 派生;默认 base=8px → 4/8/14/16)。 */
|
|
1438
1506
|
const RADIUS_FACTORS = {
|
|
1439
1507
|
sm: .5,
|
|
@@ -1489,6 +1557,48 @@ function buildRadiusRecipes() {
|
|
|
1489
1557
|
})
|
|
1490
1558
|
];
|
|
1491
1559
|
}
|
|
1560
|
+
/** Existing public placeholder geometry: font-relative text and calibrated media. */
|
|
1561
|
+
function buildPlaceholderSizeRecipes() {
|
|
1562
|
+
return [ref([
|
|
1563
|
+
"size",
|
|
1564
|
+
"placeholderTextHeight",
|
|
1565
|
+
"base"
|
|
1566
|
+
], {
|
|
1567
|
+
kind: "literal",
|
|
1568
|
+
value: "1em"
|
|
1569
|
+
}, {
|
|
1570
|
+
source: "CSS Values font-relative em unit; qw-ui Skeleton public text default",
|
|
1571
|
+
rationale: "Text placeholder follows inherited font size without adding a theme seed."
|
|
1572
|
+
}), ref([
|
|
1573
|
+
"size",
|
|
1574
|
+
"placeholderMediaHeight",
|
|
1575
|
+
"base"
|
|
1576
|
+
], {
|
|
1577
|
+
kind: "literal",
|
|
1578
|
+
value: "120px"
|
|
1579
|
+
}, {
|
|
1580
|
+
source: "qw-ui Skeleton existing public media placeholder geometry; specs/036-native-display",
|
|
1581
|
+
rationale: "Preserves the existing calibrated media default independently of control/avatar scales."
|
|
1582
|
+
})];
|
|
1583
|
+
}
|
|
1584
|
+
/** Loading logo boxes follow the independent existing public size contract. */
|
|
1585
|
+
function buildLoadingSizeRecipes() {
|
|
1586
|
+
return Object.entries({
|
|
1587
|
+
sm: 32,
|
|
1588
|
+
md: 48,
|
|
1589
|
+
lg: 60
|
|
1590
|
+
}).map(([size, value]) => ref([
|
|
1591
|
+
"size",
|
|
1592
|
+
"loadingLogoSize",
|
|
1593
|
+
size
|
|
1594
|
+
], {
|
|
1595
|
+
kind: "literal",
|
|
1596
|
+
value: `${value}px`
|
|
1597
|
+
}, {
|
|
1598
|
+
source: "qw-ui Loading public logo-size contract; specs/037-native-loading",
|
|
1599
|
+
rationale: "Independent calibrated logo boxes must not change with unrelated control or icon size seeds."
|
|
1600
|
+
}));
|
|
1601
|
+
}
|
|
1492
1602
|
/** 6. 控件/图标尺寸:md = base 直通,sm/lg = base ∓ spacing.step × n(控件 ×2、图标 ×1)。 */
|
|
1493
1603
|
function buildControlIconSizeRecipes() {
|
|
1494
1604
|
const step = "size.spacing.step";
|
|
@@ -1674,6 +1784,18 @@ function buildLineHeightRecipes() {
|
|
|
1674
1784
|
kind: "alias",
|
|
1675
1785
|
seedRef: "typography.lineHeight.base"
|
|
1676
1786
|
}),
|
|
1787
|
+
ref([
|
|
1788
|
+
"typography",
|
|
1789
|
+
"lineHeight",
|
|
1790
|
+
"comfortable"
|
|
1791
|
+
], {
|
|
1792
|
+
kind: "literal",
|
|
1793
|
+
value: 1.625
|
|
1794
|
+
}, {
|
|
1795
|
+
sourceKind: "design-calibrated",
|
|
1796
|
+
source: "Figma RihMzcoamEChrLxQa0xjmH / I22378:53258;17214:12764 / frozen scene-22378-53247-reference.tsx",
|
|
1797
|
+
rationale: "Exact 26px / 16px title ratio; independent of lineHeight Seed anchor."
|
|
1798
|
+
}),
|
|
1677
1799
|
ref([
|
|
1678
1800
|
"typography",
|
|
1679
1801
|
"lineHeight",
|
|
@@ -1820,6 +1942,37 @@ function buildMotionRecipes() {
|
|
|
1820
1942
|
seedRef: "motion.duration.base",
|
|
1821
1943
|
factor: DURATION_FACTORS.slow
|
|
1822
1944
|
}),
|
|
1945
|
+
ref([
|
|
1946
|
+
"motion",
|
|
1947
|
+
"duration",
|
|
1948
|
+
"shimmer"
|
|
1949
|
+
], {
|
|
1950
|
+
kind: "scale",
|
|
1951
|
+
seedRef: "motion.duration.base",
|
|
1952
|
+
factor: 10
|
|
1953
|
+
}),
|
|
1954
|
+
ref([
|
|
1955
|
+
"motion",
|
|
1956
|
+
"easing",
|
|
1957
|
+
"linear"
|
|
1958
|
+
], {
|
|
1959
|
+
kind: "literal",
|
|
1960
|
+
value: "linear"
|
|
1961
|
+
}, {
|
|
1962
|
+
source: "CSS Easing Functions: linear identity function",
|
|
1963
|
+
rationale: "Uniform decorative spin without an entrance or symmetric pulse curve."
|
|
1964
|
+
}),
|
|
1965
|
+
ref([
|
|
1966
|
+
"motion",
|
|
1967
|
+
"easing",
|
|
1968
|
+
"symmetric"
|
|
1969
|
+
], {
|
|
1970
|
+
kind: "literal",
|
|
1971
|
+
value: "ease-in-out"
|
|
1972
|
+
}, {
|
|
1973
|
+
source: "CSS Easing Functions: ease-in-out equals cubic-bezier(0.42, 0, 0.58, 1)",
|
|
1974
|
+
rationale: "Symmetric repeating shimmer preserves the existing easing; distinct from entrance easing."
|
|
1975
|
+
}),
|
|
1823
1976
|
ref([
|
|
1824
1977
|
"motion",
|
|
1825
1978
|
"easing",
|
|
@@ -1852,6 +2005,9 @@ function allReferenceRecipes() {
|
|
|
1852
2005
|
return [
|
|
1853
2006
|
...buildColorRampRecipes(),
|
|
1854
2007
|
...buildSpacingRecipes(),
|
|
2008
|
+
...buildSafeAreaInsetRecipes(),
|
|
2009
|
+
...buildPlaceholderSizeRecipes(),
|
|
2010
|
+
...buildLoadingSizeRecipes(),
|
|
1855
2011
|
...buildRadiusRecipes(),
|
|
1856
2012
|
...buildControlIconSizeRecipes(),
|
|
1857
2013
|
...buildStrokeWidthRecipes(),
|
|
@@ -1862,6 +2018,15 @@ function allReferenceRecipes() {
|
|
|
1862
2018
|
...buildZIndexRecipes(),
|
|
1863
2019
|
...buildTypographyRecipes(),
|
|
1864
2020
|
...buildMotionRecipes(),
|
|
2021
|
+
ref([
|
|
2022
|
+
"effect",
|
|
2023
|
+
"blur",
|
|
2024
|
+
"sm"
|
|
2025
|
+
], {
|
|
2026
|
+
kind: "scale",
|
|
2027
|
+
seedRef: "size.spacing.step",
|
|
2028
|
+
factor: .5
|
|
2029
|
+
}),
|
|
1865
2030
|
...buildShadowRecipes()
|
|
1866
2031
|
];
|
|
1867
2032
|
}
|
|
@@ -1890,40 +2055,44 @@ function pick(tokens, dottedRefPath) {
|
|
|
1890
2055
|
function semVar(path) {
|
|
1891
2056
|
return toVar("sem", path);
|
|
1892
2057
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
2058
|
+
/** Create independent ordinary role tables; prefix compression preserves each literal reference. */
|
|
2059
|
+
function referenceRoles(prefix, values) {
|
|
2060
|
+
return Object.fromEntries(Object.entries(values).map(([role, value]) => [role, `${prefix}.${value}`]));
|
|
2061
|
+
}
|
|
2062
|
+
const RADIUS_ROLES = /* @__PURE__ */ referenceRoles("size.radius", {
|
|
2063
|
+
sm: "sm",
|
|
2064
|
+
control: "md",
|
|
2065
|
+
card: "lg",
|
|
2066
|
+
xl: "xl",
|
|
2067
|
+
pill: "full",
|
|
2068
|
+
full: "full"
|
|
2069
|
+
});
|
|
2070
|
+
const CONTROL_HEIGHT_ROLES = /* @__PURE__ */ referenceRoles("size.controlSize", {
|
|
2071
|
+
sm: "sm",
|
|
2072
|
+
md: "md",
|
|
2073
|
+
lg: "lg"
|
|
2074
|
+
});
|
|
2075
|
+
const ICON_SIZE_ROLES = /* @__PURE__ */ referenceRoles("size.iconSize", {
|
|
2076
|
+
sm: "sm",
|
|
2077
|
+
md: "md",
|
|
2078
|
+
lg: "lg"
|
|
2079
|
+
});
|
|
2080
|
+
const ACTION_CONTROL_HEIGHT_ROLES = /* @__PURE__ */ referenceRoles("size.actionControlHeight", {
|
|
2081
|
+
"2xs": "2xs",
|
|
2082
|
+
xs: "xs",
|
|
2083
|
+
sm: "sm",
|
|
2084
|
+
md: "md",
|
|
2085
|
+
lg: "lg",
|
|
2086
|
+
xl: "xl"
|
|
2087
|
+
});
|
|
2088
|
+
const ACTION_CONTROL_PADDING_INLINE_ROLES = /* @__PURE__ */ referenceRoles("size.spacing", {
|
|
2089
|
+
"2xs": "2",
|
|
2090
|
+
xs: "2",
|
|
2091
|
+
sm: "4",
|
|
2092
|
+
md: "4",
|
|
2093
|
+
lg: "5",
|
|
2094
|
+
xl: "8"
|
|
2095
|
+
});
|
|
1927
2096
|
const ACTION_CONTROL_ICON_ROLES = {
|
|
1928
2097
|
"2xs": "size.actionControlIcon.2xs",
|
|
1929
2098
|
xs: "size.iconSize.sm",
|
|
@@ -1932,124 +2101,123 @@ const ACTION_CONTROL_ICON_ROLES = {
|
|
|
1932
2101
|
lg: "size.iconSize.sm",
|
|
1933
2102
|
xl: "size.iconSize.md"
|
|
1934
2103
|
};
|
|
1935
|
-
const ACTION_CONTROL_GAP_ROLES = {
|
|
1936
|
-
"2xs": "
|
|
1937
|
-
xs: "
|
|
1938
|
-
sm: "
|
|
1939
|
-
md: "
|
|
1940
|
-
lg: "
|
|
1941
|
-
xl: "
|
|
1942
|
-
};
|
|
1943
|
-
const BORDER_WIDTH_ROLES = {
|
|
1944
|
-
default: "
|
|
1945
|
-
strong: "
|
|
1946
|
-
};
|
|
1947
|
-
const DIVIDER_WIDTH_ROLES = {
|
|
1948
|
-
thin: "
|
|
1949
|
-
default: "
|
|
1950
|
-
};
|
|
1951
|
-
const FOCUS_RING_ROLES = {
|
|
1952
|
-
width: "
|
|
1953
|
-
offset: "
|
|
1954
|
-
};
|
|
1955
|
-
const INDICATOR_ROLES = { loading: "
|
|
2104
|
+
const ACTION_CONTROL_GAP_ROLES = /* @__PURE__ */ referenceRoles("size.spacing", {
|
|
2105
|
+
"2xs": "1",
|
|
2106
|
+
xs: "1",
|
|
2107
|
+
sm: "2",
|
|
2108
|
+
md: "2",
|
|
2109
|
+
lg: "2",
|
|
2110
|
+
xl: "2"
|
|
2111
|
+
});
|
|
2112
|
+
const BORDER_WIDTH_ROLES = /* @__PURE__ */ referenceRoles("size.strokeWidth", {
|
|
2113
|
+
default: "base",
|
|
2114
|
+
strong: "double"
|
|
2115
|
+
});
|
|
2116
|
+
const DIVIDER_WIDTH_ROLES = /* @__PURE__ */ referenceRoles("size.strokeWidth", {
|
|
2117
|
+
thin: "half",
|
|
2118
|
+
default: "base"
|
|
2119
|
+
});
|
|
2120
|
+
const FOCUS_RING_ROLES = /* @__PURE__ */ referenceRoles("size.strokeWidth", {
|
|
2121
|
+
width: "double",
|
|
2122
|
+
offset: "double"
|
|
2123
|
+
});
|
|
2124
|
+
const INDICATOR_ROLES = /* @__PURE__ */ referenceRoles("size.strokeWidth", { loading: "double" });
|
|
1956
2125
|
/** 展示类专用尺寸:Avatar 直径三档(Figma 头像 S/M/L)。 */
|
|
1957
|
-
const AVATAR_DIAMETER_ROLES = {
|
|
1958
|
-
sm: "
|
|
1959
|
-
md: "
|
|
1960
|
-
lg: "
|
|
1961
|
-
};
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
const Z_INDEX_ROLES = {
|
|
1968
|
-
dropdown: "size.zIndex.1",
|
|
1969
|
-
sticky: "size.zIndex.2",
|
|
1970
|
-
overlay: "size.zIndex.3",
|
|
1971
|
-
toast: "size.zIndex.4"
|
|
1972
|
-
};
|
|
1973
|
-
const MOTION_DURATION_ROLES = {
|
|
1974
|
-
fast: "motion.duration.fast",
|
|
1975
|
-
base: "motion.duration.base",
|
|
1976
|
-
slow: "motion.duration.slow"
|
|
2126
|
+
const AVATAR_DIAMETER_ROLES = /* @__PURE__ */ referenceRoles("size.avatarDiameter", {
|
|
2127
|
+
sm: "sm",
|
|
2128
|
+
md: "md",
|
|
2129
|
+
lg: "lg"
|
|
2130
|
+
});
|
|
2131
|
+
/** Independent placeholder roles reference T2 directly, never other T3 roles. */
|
|
2132
|
+
const SKELETON_SIZE_ROLES = {
|
|
2133
|
+
textHeight: "size.placeholderTextHeight.base",
|
|
2134
|
+
rectHeight: "size.placeholderMediaHeight.base",
|
|
2135
|
+
circleDiameter: "size.avatarDiameter.sm"
|
|
1977
2136
|
};
|
|
2137
|
+
const MOTION_EASING_ROLES = /* @__PURE__ */ referenceRoles("motion.easing", {
|
|
2138
|
+
standard: "standard",
|
|
2139
|
+
symmetric: "symmetric",
|
|
2140
|
+
linear: "linear"
|
|
2141
|
+
});
|
|
2142
|
+
const LOADING_SIZE_ROLES = /* @__PURE__ */ referenceRoles("size.loadingLogoSize", {
|
|
2143
|
+
sm: "sm",
|
|
2144
|
+
md: "md",
|
|
2145
|
+
lg: "lg"
|
|
2146
|
+
});
|
|
2147
|
+
const LAYOUT_GAP_ROLES = /* @__PURE__ */ referenceRoles("size.spacing", {
|
|
2148
|
+
sm: "2",
|
|
2149
|
+
md: "4",
|
|
2150
|
+
lg: "6"
|
|
2151
|
+
});
|
|
2152
|
+
const SAFE_AREA_INSET_ROLES = /* @__PURE__ */ referenceRoles("size.safeAreaInset", {
|
|
2153
|
+
top: "top",
|
|
2154
|
+
right: "right",
|
|
2155
|
+
bottom: "bottom",
|
|
2156
|
+
left: "left"
|
|
2157
|
+
});
|
|
2158
|
+
const SAFE_AREA_MINIMUM_ROLES = /* @__PURE__ */ referenceRoles("size.spacing", {
|
|
2159
|
+
none: "0",
|
|
2160
|
+
sm: "2",
|
|
2161
|
+
md: "4",
|
|
2162
|
+
lg: "6"
|
|
2163
|
+
});
|
|
2164
|
+
const INSET_STACK_ROLES = /* @__PURE__ */ referenceRoles("size.spacing", {
|
|
2165
|
+
sm: "2",
|
|
2166
|
+
md: "4",
|
|
2167
|
+
lg: "6"
|
|
2168
|
+
});
|
|
2169
|
+
const Z_INDEX_ROLES = /* @__PURE__ */ referenceRoles("size.zIndex", {
|
|
2170
|
+
dropdown: "1",
|
|
2171
|
+
sticky: "2",
|
|
2172
|
+
overlay: "3",
|
|
2173
|
+
toast: "4"
|
|
2174
|
+
});
|
|
2175
|
+
const MOTION_DURATION_ROLES = /* @__PURE__ */ referenceRoles("motion.duration", {
|
|
2176
|
+
fast: "fast",
|
|
2177
|
+
base: "base",
|
|
2178
|
+
slow: "slow",
|
|
2179
|
+
shimmer: "shimmer",
|
|
2180
|
+
spin: "shimmer"
|
|
2181
|
+
});
|
|
1978
2182
|
/** 字体族角色:text(正文缺省)/ number(数字数据)/ code(等宽)。 */
|
|
1979
|
-
const FONT_FAMILY_ROLES = {
|
|
1980
|
-
text: "
|
|
1981
|
-
number: "
|
|
1982
|
-
code: "
|
|
1983
|
-
};
|
|
2183
|
+
const FONT_FAMILY_ROLES = /* @__PURE__ */ referenceRoles("typography.fontFamily", {
|
|
2184
|
+
text: "text",
|
|
2185
|
+
number: "number",
|
|
2186
|
+
code: "code"
|
|
2187
|
+
});
|
|
1984
2188
|
const T_LETTER = "typography.letterSpacing.base";
|
|
2189
|
+
/** Fresh records retain independent mutable role values and original property order. */
|
|
2190
|
+
function typographyRole(size, weight = "regular", lineHeight = "normal", family = "text") {
|
|
2191
|
+
return {
|
|
2192
|
+
fontFamilyRef: `typography.fontFamily.${family}`,
|
|
2193
|
+
fontSizeRef: `typography.fontSize.${size}`,
|
|
2194
|
+
fontWeightRef: `typography.fontWeight.${weight}`,
|
|
2195
|
+
lineHeightRef: `typography.lineHeight.${lineHeight}`,
|
|
2196
|
+
letterSpacingRef: T_LETTER
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
1985
2199
|
/** typography.* 复合角色:每个字段各自引用 Reference(无任何裸字面量)。 */
|
|
1986
2200
|
const TYPOGRAPHY_ROLES = {
|
|
1987
|
-
body:
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
bodyStrong: {
|
|
1995
|
-
fontFamilyRef: "typography.fontFamily.text",
|
|
1996
|
-
fontSizeRef: "typography.fontSize.base",
|
|
1997
|
-
fontWeightRef: "typography.fontWeight.medium",
|
|
1998
|
-
lineHeightRef: "typography.lineHeight.normal",
|
|
1999
|
-
letterSpacingRef: T_LETTER
|
|
2000
|
-
},
|
|
2001
|
-
headingSm: {
|
|
2002
|
-
fontFamilyRef: "typography.fontFamily.text",
|
|
2003
|
-
fontSizeRef: "typography.fontSize.lg",
|
|
2004
|
-
fontWeightRef: "typography.fontWeight.semibold",
|
|
2005
|
-
lineHeightRef: "typography.lineHeight.tight",
|
|
2006
|
-
letterSpacingRef: T_LETTER
|
|
2007
|
-
},
|
|
2008
|
-
headingMd: {
|
|
2009
|
-
fontFamilyRef: "typography.fontFamily.text",
|
|
2010
|
-
fontSizeRef: "typography.fontSize.xl",
|
|
2011
|
-
fontWeightRef: "typography.fontWeight.semibold",
|
|
2012
|
-
lineHeightRef: "typography.lineHeight.tight",
|
|
2013
|
-
letterSpacingRef: T_LETTER
|
|
2014
|
-
},
|
|
2015
|
-
headingLg: {
|
|
2016
|
-
fontFamilyRef: "typography.fontFamily.text",
|
|
2017
|
-
fontSizeRef: "typography.fontSize.2xl",
|
|
2018
|
-
fontWeightRef: "typography.fontWeight.semibold",
|
|
2019
|
-
lineHeightRef: "typography.lineHeight.tight",
|
|
2020
|
-
letterSpacingRef: T_LETTER
|
|
2021
|
-
},
|
|
2022
|
-
caption: {
|
|
2023
|
-
fontFamilyRef: "typography.fontFamily.text",
|
|
2024
|
-
fontSizeRef: "typography.fontSize.sm",
|
|
2025
|
-
fontWeightRef: "typography.fontWeight.regular",
|
|
2026
|
-
lineHeightRef: "typography.lineHeight.normal",
|
|
2027
|
-
letterSpacingRef: T_LETTER
|
|
2028
|
-
},
|
|
2201
|
+
body: /* @__PURE__ */ typographyRole("base"),
|
|
2202
|
+
bodyStrong: /* @__PURE__ */ typographyRole("base", "medium"),
|
|
2203
|
+
productTitle: /* @__PURE__ */ typographyRole("lg", "semibold", "comfortable"),
|
|
2204
|
+
headingSm: /* @__PURE__ */ typographyRole("lg", "semibold", "tight"),
|
|
2205
|
+
headingMd: /* @__PURE__ */ typographyRole("xl", "semibold", "tight"),
|
|
2206
|
+
headingLg: /* @__PURE__ */ typographyRole("2xl", "semibold", "tight"),
|
|
2207
|
+
caption: /* @__PURE__ */ typographyRole("sm"),
|
|
2029
2208
|
/** 大正文(治理稿 T3 字段「大正文 16px · T2 M」):行高沿用 canonical 比例引擎。 */
|
|
2030
|
-
bodyLg:
|
|
2031
|
-
fontFamilyRef: "typography.fontFamily.text",
|
|
2032
|
-
fontSizeRef: "typography.fontSize.lg",
|
|
2033
|
-
fontWeightRef: "typography.fontWeight.regular",
|
|
2034
|
-
lineHeightRef: "typography.lineHeight.normal",
|
|
2035
|
-
letterSpacingRef: T_LETTER
|
|
2036
|
-
},
|
|
2209
|
+
bodyLg: /* @__PURE__ */ typographyRole("lg"),
|
|
2037
2210
|
/** 小标签(治理稿 Text/Label/Small = 11/500/16):字号取 T2 xs=11px。 */
|
|
2038
|
-
labelSm:
|
|
2039
|
-
|
|
2040
|
-
fontSizeRef: "typography.fontSize.xs",
|
|
2041
|
-
fontWeightRef: "typography.fontWeight.medium",
|
|
2042
|
-
lineHeightRef: "typography.lineHeight.normal",
|
|
2043
|
-
letterSpacingRef: T_LETTER
|
|
2044
|
-
},
|
|
2045
|
-
code: {
|
|
2046
|
-
fontFamilyRef: "typography.fontFamily.code",
|
|
2047
|
-
fontSizeRef: "typography.fontSize.sm",
|
|
2048
|
-
fontWeightRef: "typography.fontWeight.regular",
|
|
2049
|
-
lineHeightRef: "typography.lineHeight.normal",
|
|
2050
|
-
letterSpacingRef: T_LETTER
|
|
2051
|
-
}
|
|
2211
|
+
labelSm: /* @__PURE__ */ typographyRole("xs", "medium"),
|
|
2212
|
+
code: /* @__PURE__ */ typographyRole("sm", "regular", "normal", "code")
|
|
2052
2213
|
};
|
|
2214
|
+
const typographyProjectionFields = [...[
|
|
2215
|
+
"fontFamily",
|
|
2216
|
+
"fontSize",
|
|
2217
|
+
"fontWeight",
|
|
2218
|
+
"lineHeight",
|
|
2219
|
+
"letterSpacing"
|
|
2220
|
+
]];
|
|
2053
2221
|
/**
|
|
2054
2222
|
* 颜色角色的 Semantic 变量路径:绝大多数角色落在 `--qw-sem-color-*` 下;
|
|
2055
2223
|
* `effect.shadow.*.color` 是复合阴影的颜色分量,对应 Figma 变量
|
|
@@ -2066,6 +2234,26 @@ const SHADOW_COMPOSITE_ROLES = {
|
|
|
2066
2234
|
floating: "md",
|
|
2067
2235
|
dialog: "lg"
|
|
2068
2236
|
};
|
|
2237
|
+
/** Keep source table references live; preserve projection order without repeated loops. */
|
|
2238
|
+
const SIZE_ROLE_GROUPS = [
|
|
2239
|
+
["radius", RADIUS_ROLES],
|
|
2240
|
+
["controlHeight", CONTROL_HEIGHT_ROLES],
|
|
2241
|
+
["iconSize", ICON_SIZE_ROLES],
|
|
2242
|
+
["actionControlHeight", ACTION_CONTROL_HEIGHT_ROLES],
|
|
2243
|
+
["actionControlPaddingInline", ACTION_CONTROL_PADDING_INLINE_ROLES],
|
|
2244
|
+
["actionControlIcon", ACTION_CONTROL_ICON_ROLES],
|
|
2245
|
+
["actionControlGap", ACTION_CONTROL_GAP_ROLES],
|
|
2246
|
+
["borderWidth", BORDER_WIDTH_ROLES],
|
|
2247
|
+
["dividerWidth", DIVIDER_WIDTH_ROLES],
|
|
2248
|
+
["focusRing", FOCUS_RING_ROLES],
|
|
2249
|
+
["indicator", INDICATOR_ROLES],
|
|
2250
|
+
["avatarDiameter", AVATAR_DIAMETER_ROLES],
|
|
2251
|
+
["layoutGap", LAYOUT_GAP_ROLES],
|
|
2252
|
+
["safeAreaInset", SAFE_AREA_INSET_ROLES],
|
|
2253
|
+
["safeAreaMinimum", SAFE_AREA_MINIMUM_ROLES],
|
|
2254
|
+
["loading", LOADING_SIZE_ROLES],
|
|
2255
|
+
["skeleton", SKELETON_SIZE_ROLES]
|
|
2256
|
+
];
|
|
2069
2257
|
/**
|
|
2070
2258
|
* 全量 Semantic 角色的结构化血缘表——"角色 → 引用的 Reference 路径(含 light/dark 分支)"。
|
|
2071
2259
|
* 与 buildSemanticStructural/buildSemanticColor 的产出一一对应(顺序一致)。
|
|
@@ -2078,64 +2266,9 @@ function semanticRoleEntries() {
|
|
|
2078
2266
|
cssVar: semVar(path),
|
|
2079
2267
|
refPath
|
|
2080
2268
|
});
|
|
2081
|
-
for (const [role, refPath] of Object.entries(
|
|
2082
|
-
"size",
|
|
2083
|
-
"radius",
|
|
2084
|
-
role
|
|
2085
|
-
], refPath);
|
|
2086
|
-
for (const [role, refPath] of Object.entries(CONTROL_HEIGHT_ROLES)) structural([
|
|
2087
|
-
"size",
|
|
2088
|
-
"controlHeight",
|
|
2089
|
-
role
|
|
2090
|
-
], refPath);
|
|
2091
|
-
for (const [role, refPath] of Object.entries(ICON_SIZE_ROLES)) structural([
|
|
2092
|
-
"size",
|
|
2093
|
-
"iconSize",
|
|
2094
|
-
role
|
|
2095
|
-
], refPath);
|
|
2096
|
-
for (const [role, refPath] of Object.entries(ACTION_CONTROL_HEIGHT_ROLES)) structural([
|
|
2097
|
-
"size",
|
|
2098
|
-
"actionControlHeight",
|
|
2099
|
-
role
|
|
2100
|
-
], refPath);
|
|
2101
|
-
for (const [role, refPath] of Object.entries(ACTION_CONTROL_PADDING_INLINE_ROLES)) structural([
|
|
2269
|
+
for (const [group, table] of SIZE_ROLE_GROUPS) for (const [role, refPath] of Object.entries(table)) structural([
|
|
2102
2270
|
"size",
|
|
2103
|
-
|
|
2104
|
-
role
|
|
2105
|
-
], refPath);
|
|
2106
|
-
for (const [role, refPath] of Object.entries(ACTION_CONTROL_ICON_ROLES)) structural([
|
|
2107
|
-
"size",
|
|
2108
|
-
"actionControlIcon",
|
|
2109
|
-
role
|
|
2110
|
-
], refPath);
|
|
2111
|
-
for (const [role, refPath] of Object.entries(ACTION_CONTROL_GAP_ROLES)) structural([
|
|
2112
|
-
"size",
|
|
2113
|
-
"actionControlGap",
|
|
2114
|
-
role
|
|
2115
|
-
], refPath);
|
|
2116
|
-
for (const [role, refPath] of Object.entries(BORDER_WIDTH_ROLES)) structural([
|
|
2117
|
-
"size",
|
|
2118
|
-
"borderWidth",
|
|
2119
|
-
role
|
|
2120
|
-
], refPath);
|
|
2121
|
-
for (const [role, refPath] of Object.entries(DIVIDER_WIDTH_ROLES)) structural([
|
|
2122
|
-
"size",
|
|
2123
|
-
"dividerWidth",
|
|
2124
|
-
role
|
|
2125
|
-
], refPath);
|
|
2126
|
-
for (const [role, refPath] of Object.entries(FOCUS_RING_ROLES)) structural([
|
|
2127
|
-
"size",
|
|
2128
|
-
"focusRing",
|
|
2129
|
-
role
|
|
2130
|
-
], refPath);
|
|
2131
|
-
for (const [role, refPath] of Object.entries(INDICATOR_ROLES)) structural([
|
|
2132
|
-
"size",
|
|
2133
|
-
"indicator",
|
|
2134
|
-
role
|
|
2135
|
-
], refPath);
|
|
2136
|
-
for (const [role, refPath] of Object.entries(AVATAR_DIAMETER_ROLES)) structural([
|
|
2137
|
-
"size",
|
|
2138
|
-
"avatarDiameter",
|
|
2271
|
+
group,
|
|
2139
2272
|
role
|
|
2140
2273
|
], refPath);
|
|
2141
2274
|
for (const [role, refPath] of Object.entries(INSET_STACK_ROLES)) {
|
|
@@ -2165,43 +2298,26 @@ function semanticRoleEntries() {
|
|
|
2165
2298
|
"fontFamily",
|
|
2166
2299
|
role
|
|
2167
2300
|
], refPath);
|
|
2168
|
-
for (const [role, spec] of Object.entries(TYPOGRAPHY_ROLES))
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
], spec.fontFamilyRef);
|
|
2174
|
-
structural([
|
|
2175
|
-
"typography",
|
|
2176
|
-
role,
|
|
2177
|
-
"fontSize"
|
|
2178
|
-
], spec.fontSizeRef);
|
|
2179
|
-
structural([
|
|
2180
|
-
"typography",
|
|
2181
|
-
role,
|
|
2182
|
-
"fontWeight"
|
|
2183
|
-
], spec.fontWeightRef);
|
|
2184
|
-
structural([
|
|
2185
|
-
"typography",
|
|
2186
|
-
role,
|
|
2187
|
-
"lineHeight"
|
|
2188
|
-
], spec.lineHeightRef);
|
|
2189
|
-
structural([
|
|
2190
|
-
"typography",
|
|
2191
|
-
role,
|
|
2192
|
-
"letterSpacing"
|
|
2193
|
-
], spec.letterSpacingRef);
|
|
2194
|
-
}
|
|
2301
|
+
for (const [role, spec] of Object.entries(TYPOGRAPHY_ROLES)) for (const field of typographyProjectionFields) structural([
|
|
2302
|
+
"typography",
|
|
2303
|
+
role,
|
|
2304
|
+
field
|
|
2305
|
+
], spec[`${field}Ref`]);
|
|
2195
2306
|
for (const [role, refPath] of Object.entries(MOTION_DURATION_ROLES)) structural([
|
|
2196
2307
|
"motion",
|
|
2197
2308
|
"duration",
|
|
2198
2309
|
role
|
|
2199
2310
|
], refPath);
|
|
2200
|
-
structural([
|
|
2311
|
+
for (const [role, refPath] of Object.entries(MOTION_EASING_ROLES)) structural([
|
|
2201
2312
|
"motion",
|
|
2202
2313
|
"easing",
|
|
2203
|
-
|
|
2204
|
-
],
|
|
2314
|
+
role
|
|
2315
|
+
], refPath);
|
|
2316
|
+
structural([
|
|
2317
|
+
"effect",
|
|
2318
|
+
"blur",
|
|
2319
|
+
"media-control"
|
|
2320
|
+
], "effect.blur.sm");
|
|
2205
2321
|
for (const [path, refs] of Object.entries(COLOR_ROLES)) {
|
|
2206
2322
|
const segs = colorRoleSemPath(path);
|
|
2207
2323
|
out.push({
|
|
@@ -2363,6 +2479,7 @@ function derivationToCssExpr(d) {
|
|
|
2363
2479
|
case "seedAlpha": return `rgb(from var(${seedVar(d.seedRef)}) r g b / ${round4$1(d.alpha)})`;
|
|
2364
2480
|
case "alphaScale": return `rgb(${d.channel === "black" ? "0 0 0" : "255 255 255"} / calc(var(${seedVar(d.stepRef)}) * ${d.multiplier}))`;
|
|
2365
2481
|
case "literal": return String(d.value);
|
|
2482
|
+
case "cssEnvironment": return `env(${d.name}, ${d.fallback})`;
|
|
2366
2483
|
case "shadowLayer": {
|
|
2367
2484
|
const s = shadowShapeExprs(d.level);
|
|
2368
2485
|
const alpha = `calc(var(${seedVar("size.opacity.alphaStep")}) * ${SHADOW_LEVELS[d.level].alphaMult})`;
|
|
@@ -2478,12 +2595,20 @@ function buildT2() {
|
|
|
2478
2595
|
});
|
|
2479
2596
|
t2[seed] = steps;
|
|
2480
2597
|
}
|
|
2598
|
+
t2.black[T2_BLACK_CONTRAST_ENDPOINT.step] = t2Token(colorValue(T2_BLACK_CONTRAST_ENDPOINT.value), {
|
|
2599
|
+
sourceKind: "standard-constant",
|
|
2600
|
+
seedRefs: [],
|
|
2601
|
+
source: T2_BLACK_CONTRAST_ENDPOINT.source,
|
|
2602
|
+
rationale: T2_BLACK_CONTRAST_ENDPOINT.rationale,
|
|
2603
|
+
formula: "= sRGB(0, 0, 0), alpha 1"
|
|
2604
|
+
});
|
|
2481
2605
|
return t2;
|
|
2482
2606
|
}
|
|
2483
2607
|
function buildT3() {
|
|
2484
2608
|
const t3 = {};
|
|
2485
2609
|
for (const [role, refs] of Object.entries(FIGMA_T3_COLOR_ROLES)) {
|
|
2486
2610
|
const segs = role.split(".");
|
|
2611
|
+
const approval = role === "content.on-brand" ? "RFC0012 user 2026-10-12" : role === "content.danger" ? "RFC0026" : role === "border.control" ? "SPEC085" : void 0;
|
|
2487
2612
|
const node = {
|
|
2488
2613
|
$type: "color",
|
|
2489
2614
|
$value: t2Ref(refs.light),
|
|
@@ -2492,7 +2617,11 @@ function buildT3() {
|
|
|
2492
2617
|
modes: {
|
|
2493
2618
|
light: t2Ref(refs.light),
|
|
2494
2619
|
dark: t2Ref(refs.dark)
|
|
2495
|
-
}
|
|
2620
|
+
},
|
|
2621
|
+
...approval ? {
|
|
2622
|
+
approval,
|
|
2623
|
+
figmaSync: "pending"
|
|
2624
|
+
} : {}
|
|
2496
2625
|
} }
|
|
2497
2626
|
};
|
|
2498
2627
|
let cur = t3;
|
|
@@ -2514,7 +2643,11 @@ function buildFigmaColorSnapshot() {
|
|
|
2514
2643
|
collection: "Color",
|
|
2515
2644
|
figmaNode: "22258:49986",
|
|
2516
2645
|
generated: true,
|
|
2517
|
-
owner: "design-system"
|
|
2646
|
+
owner: "design-system",
|
|
2647
|
+
localExtensions: {
|
|
2648
|
+
rfc: "0012",
|
|
2649
|
+
figmaSync: "pending"
|
|
2650
|
+
}
|
|
2518
2651
|
} },
|
|
2519
2652
|
qw: {
|
|
2520
2653
|
t1: buildT1(),
|
|
@@ -2587,17 +2720,18 @@ function provenanceOf(leaf) {
|
|
|
2587
2720
|
const ext = extensionObject(leaf);
|
|
2588
2721
|
return isObject(ext.provenance) ? ext.provenance : {};
|
|
2589
2722
|
}
|
|
2590
|
-
|
|
2723
|
+
/** Shared structural checks preserve the same short-circuit/getter order in both guards. */
|
|
2724
|
+
function hasColorComponents(value) {
|
|
2591
2725
|
if (!isObject(value)) return false;
|
|
2592
2726
|
if (value.colorSpace !== "srgb" && value.colorSpace !== "oklch") return false;
|
|
2593
2727
|
if (!Array.isArray(value.components) || value.components.length !== 3) return false;
|
|
2594
|
-
return
|
|
2728
|
+
return true;
|
|
2729
|
+
}
|
|
2730
|
+
function isSolidColorValue(value) {
|
|
2731
|
+
return hasColorComponents(value) && value.alpha === 1;
|
|
2595
2732
|
}
|
|
2596
2733
|
function isColorLikeValue(value) {
|
|
2597
|
-
|
|
2598
|
-
if (value.colorSpace !== "srgb" && value.colorSpace !== "oklch") return false;
|
|
2599
|
-
if (!Array.isArray(value.components) || value.components.length !== 3) return false;
|
|
2600
|
-
return typeof value.alpha === "number" && value.alpha >= 0 && value.alpha <= 1;
|
|
2734
|
+
return hasColorComponents(value) && typeof value.alpha === "number" && value.alpha >= 0 && value.alpha <= 1;
|
|
2601
2735
|
}
|
|
2602
2736
|
function validateNoUnexpectedName(path, errors) {
|
|
2603
2737
|
const joined = pathKey(path);
|
|
@@ -2608,18 +2742,20 @@ function validateT3Path(path, errors) {
|
|
|
2608
2742
|
const joined = pathKey(path);
|
|
2609
2743
|
for (const segment of path.slice(2)) if (!T3_SEGMENT.test(segment)) errors.push(`${joined}: T3 semantic segment "${segment}" must use kebab-case words without numeric suffixes`);
|
|
2610
2744
|
}
|
|
2611
|
-
/**
|
|
2745
|
+
/** Existing scales plus the explicitly approved RFC0012 standard endpoint. */
|
|
2612
2746
|
function classifyT2Step(step) {
|
|
2613
2747
|
if (step === "base") return "base";
|
|
2614
2748
|
if (T2_ALPHA_SET.has(step)) return "alpha";
|
|
2615
2749
|
if (T2_OKLCH_SET.has(step)) return "oklch";
|
|
2750
|
+
if (step === T2_BLACK_CONTRAST_ENDPOINT.step) return "constant";
|
|
2616
2751
|
return null;
|
|
2617
2752
|
}
|
|
2618
2753
|
/** 各 T2 步类对应的 provenance.sourceKind(血缘治理不变量)。 */
|
|
2619
2754
|
const T2_STEP_SOURCE_KIND = {
|
|
2620
2755
|
base: "seed-alias",
|
|
2621
2756
|
alpha: "seed-derived",
|
|
2622
|
-
oklch: "design-calibrated"
|
|
2757
|
+
oklch: "design-calibrated",
|
|
2758
|
+
constant: "standard-constant"
|
|
2623
2759
|
};
|
|
2624
2760
|
function validateT2Provenance(leaf, seed, step, errors) {
|
|
2625
2761
|
const joined = pathKey(leaf.path);
|
|
@@ -2695,6 +2831,11 @@ function validateFigmaColorTokens(doc) {
|
|
|
2695
2831
|
if (rest.length > 0 || !seed || !step) errors.push(`${joined}: T2 token must be qw/t2/{seed}/{base|alpha|oklch-step}`);
|
|
2696
2832
|
if (seed && !T1_SET.has(seed)) errors.push(`${joined}: T2 seed "${seed}" must exist in T1`);
|
|
2697
2833
|
const stepKind = step ? classifyT2Step(step) : null;
|
|
2834
|
+
if (stepKind === "constant") {
|
|
2835
|
+
if (seed !== "black") errors.push(`${joined}: RFC0012 endpoint is only permitted under black`);
|
|
2836
|
+
const value = leaf.value;
|
|
2837
|
+
if (!isObject(value) || value.colorSpace !== "srgb" || value.alpha !== 1 || !Array.isArray(value.components) || value.components.length !== 3 || value.components.some((channel) => channel !== 0)) errors.push(`${joined}: contrast endpoint must be the approved opaque sRGB black mathematical endpoint`);
|
|
2838
|
+
}
|
|
2698
2839
|
if (step && !stepKind) errors.push(`${joined}: unsupported T2 step "${step}"`);
|
|
2699
2840
|
if (!isColorLikeValue(leaf.value) && step !== "base") errors.push(`${joined}: T2 token must carry a concrete color value`);
|
|
2700
2841
|
if (seed && step && T1_SET.has(seed) && stepKind) {
|
|
@@ -2711,6 +2852,7 @@ function validateFigmaColorTokens(doc) {
|
|
|
2711
2852
|
if (missingAlpha.length) errors.push(`qw.t2.${seed}: missing alpha steps ${missingAlpha.join(", ")}`);
|
|
2712
2853
|
if (missingOklch.length) errors.push(`qw.t2.${seed}: missing OKLCH steps ${missingOklch.join(", ")}`);
|
|
2713
2854
|
if (unexpected.length) errors.push(`qw.t2.${seed}: unexpected steps ${unexpected.join(", ")}`);
|
|
2855
|
+
if (seed === "black" && !steps.has(T2_BLACK_CONTRAST_ENDPOINT.step)) errors.push("qw.t2.black: missing RFC0012 contrast endpoint");
|
|
2714
2856
|
}
|
|
2715
2857
|
const expectedT3 = new Set(figmaT3RolePaths());
|
|
2716
2858
|
const actualT3 = /* @__PURE__ */ new Set();
|
|
@@ -2718,7 +2860,7 @@ function validateFigmaColorTokens(doc) {
|
|
|
2718
2860
|
const joined = pathKey(leaf.qwPath);
|
|
2719
2861
|
actualT3.add(joined);
|
|
2720
2862
|
validateT3Path(leaf.qwPath, errors);
|
|
2721
|
-
if (!expectedT3.has(joined)) errors.push(`${joined}: unexpected T3 role (not in the
|
|
2863
|
+
if (!expectedT3.has(joined)) errors.push(`${joined}: unexpected T3 role (not in the canonical Figma/local-approved set)`);
|
|
2722
2864
|
const modes = modesOf(leaf);
|
|
2723
2865
|
const light = refToPath(modes.light);
|
|
2724
2866
|
const dark = refToPath(modes.dark);
|