@qw-ui/tokens 0.3.0-next.4 → 0.3.0-next.6

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/dist/index.js CHANGED
@@ -474,6 +474,41 @@ const T2_OKLCH_STEPS = [
474
474
  800,
475
475
  900
476
476
  ];
477
+ /**
478
+ * T2 步进锚定 Alpha:锚定 OKLCH 档位实色 + 固定 alpha 的设计校准 rgba
479
+ * (`{seed}/{step}-a{alpha}`,如 `brand/500-a20`)。只声明被 T3 角色消费的条目,
480
+ * 不作为完整刻度生成。
481
+ */
482
+ const FIGMA_T2_STEP_ALPHA = [
483
+ {
484
+ seed: "brand",
485
+ step: 500,
486
+ alpha: 20
487
+ },
488
+ {
489
+ seed: "blue",
490
+ step: 600,
491
+ alpha: 20
492
+ },
493
+ {
494
+ seed: "blue",
495
+ step: 600,
496
+ alpha: 40
497
+ },
498
+ {
499
+ seed: "red",
500
+ step: 400,
501
+ alpha: 10
502
+ },
503
+ {
504
+ seed: "red",
505
+ step: 400,
506
+ alpha: 20
507
+ }
508
+ ];
509
+ /** T2 `pure` 步进(标准常量 #000000,OLED 画布用)仅提供给 black。 */
510
+ const T2_PURE_STEP = "pure";
511
+ const T2_PURE_SEEDS = ["black"];
477
512
  const FIGMA_T2_SOLID_SCALE = {
478
513
  brand: {
479
514
  50: "#F2F6FF",
@@ -620,6 +655,11 @@ const FIGMA_T2_SOLID_SCALE = {
620
655
  900: "#200B00"
621
656
  }
622
657
  };
658
+ /**
659
+ * Figma「Color Token System」T3 语义角色表(60 个,light/dark 均引用 T2 路径)。
660
+ * 与 Figma 节点 22258:49986 逐条对齐;`effect.shadow.*.color` 为复合阴影的颜色
661
+ * 分量(对应 Figma 变量 `--qw-sem-effect-shadow-*-color`)。
662
+ */
623
663
  const FIGMA_T3_COLOR_ROLES = {
624
664
  "surface.base": {
625
665
  light: "color.white.base",
@@ -641,6 +681,26 @@ const FIGMA_T3_COLOR_ROLES = {
641
681
  light: "color.blue.50",
642
682
  dark: "color.blue.800"
643
683
  },
684
+ "surface.canvas": {
685
+ light: "color.white.base",
686
+ dark: "color.black.pure"
687
+ },
688
+ "surface.sunken": {
689
+ light: "color.gray.100",
690
+ dark: "color.gray.800"
691
+ },
692
+ "surface.selected": {
693
+ light: "color.black.a5",
694
+ dark: "color.white.a10"
695
+ },
696
+ "surface.inverse": {
697
+ light: "color.black.800",
698
+ dark: "color.black.800"
699
+ },
700
+ "surface.canvas-subtle": {
701
+ light: "color.gray.50",
702
+ dark: "color.black.pure"
703
+ },
644
704
  "content.primary": {
645
705
  light: "color.black.base",
646
706
  dark: "color.white.base"
@@ -661,6 +721,30 @@ const FIGMA_T3_COLOR_ROLES = {
661
721
  light: "color.gray.400",
662
722
  dark: "color.gray.500"
663
723
  },
724
+ "content.disabled": {
725
+ light: "color.black.a30",
726
+ dark: "color.white.a30"
727
+ },
728
+ "content.link": {
729
+ light: "color.blue.700",
730
+ dark: "color.blue.400"
731
+ },
732
+ "content.icon-subtle": {
733
+ light: "color.black.a5",
734
+ dark: "color.white.a10"
735
+ },
736
+ "content.inverse": {
737
+ light: "color.white.base",
738
+ dark: "color.black.base"
739
+ },
740
+ "content.on-solid": {
741
+ light: "color.white.base",
742
+ dark: "color.white.base"
743
+ },
744
+ "content.on-warning-subtle": {
745
+ light: "color.yellow.800",
746
+ dark: "color.yellow.200"
747
+ },
664
748
  "border.default": {
665
749
  light: "color.gray.100",
666
750
  dark: "color.gray.700"
@@ -673,6 +757,18 @@ const FIGMA_T3_COLOR_ROLES = {
673
757
  light: "color.brand.base",
674
758
  dark: "color.brand.500"
675
759
  },
760
+ "border.subtle": {
761
+ light: "color.black.a5",
762
+ dark: "color.white.a5"
763
+ },
764
+ "border.disabled": {
765
+ light: "color.black.a10",
766
+ dark: "color.white.a10"
767
+ },
768
+ "border.on-media": {
769
+ light: "color.white.base",
770
+ dark: "color.white.base"
771
+ },
676
772
  "fill.subtle": {
677
773
  light: "color.gray.50",
678
774
  dark: "color.white.a20"
@@ -689,6 +785,10 @@ const FIGMA_T3_COLOR_ROLES = {
689
785
  light: "color.gray.50",
690
786
  dark: "color.gray.900"
691
787
  },
788
+ "fill.track": {
789
+ light: "color.black.a10",
790
+ dark: "color.white.a20"
791
+ },
692
792
  "action.brand": {
693
793
  light: "color.brand.base",
694
794
  dark: "color.brand.500"
@@ -699,12 +799,44 @@ const FIGMA_T3_COLOR_ROLES = {
699
799
  },
700
800
  "action.selected": {
701
801
  light: "color.blue.a20",
702
- dark: "color.blue.a40"
802
+ dark: "color.blue.600-a40"
703
803
  },
704
804
  "action.inverse": {
705
805
  light: "color.white.base",
706
806
  dark: "color.black.base"
707
807
  },
808
+ "control-action.brand.subtle": {
809
+ light: "color.brand.a10",
810
+ dark: "color.brand.500-a20"
811
+ },
812
+ "control-action.product.subtle": {
813
+ light: "color.blue.a10",
814
+ dark: "color.blue.600-a20"
815
+ },
816
+ "control-action.danger.default": {
817
+ light: "color.red.400",
818
+ dark: "color.red.400"
819
+ },
820
+ "control-action.danger.subtle": {
821
+ light: "color.red.400-a10",
822
+ dark: "color.red.400-a20"
823
+ },
824
+ "control-action.neutral.subtle": {
825
+ light: "color.black.a5",
826
+ dark: "color.white.a10"
827
+ },
828
+ "control-selection.brand": {
829
+ light: "color.brand.a10",
830
+ dark: "color.brand.500-a20"
831
+ },
832
+ "control-selection.product": {
833
+ light: "color.blue.a10",
834
+ dark: "color.blue.600-a20"
835
+ },
836
+ "selection.text-background": {
837
+ light: "color.blue.a20",
838
+ dark: "color.blue.600-a40"
839
+ },
708
840
  "status.success": {
709
841
  light: "color.green.base",
710
842
  dark: "color.green.base"
@@ -721,13 +853,53 @@ const FIGMA_T3_COLOR_ROLES = {
721
853
  light: "color.blue.base",
722
854
  dark: "color.blue.600"
723
855
  },
856
+ "status.success-subtle": {
857
+ light: "color.green.a10",
858
+ dark: "color.green.a20"
859
+ },
860
+ "status.warning-subtle": {
861
+ light: "color.yellow.a20",
862
+ dark: "color.yellow.a20"
863
+ },
864
+ "status.danger-subtle": {
865
+ light: "color.red.400-a10",
866
+ dark: "color.red.400-a20"
867
+ },
868
+ "status.info-subtle": {
869
+ light: "color.blue.a10",
870
+ dark: "color.blue.600-a20"
871
+ },
724
872
  "overlay.scrim": {
725
873
  light: "color.black.a50",
726
874
  dark: "color.black.a70"
727
875
  },
728
876
  "overlay.guide": {
729
- light: "color.black.a70",
730
- dark: "color.black.a70"
877
+ light: "color.blue.a10",
878
+ dark: "color.blue.600-a20"
879
+ },
880
+ "overlay.media-subtle": {
881
+ light: "color.black.a40",
882
+ dark: "color.black.a40"
883
+ },
884
+ "overlay.media-strong": {
885
+ light: "color.black.a50",
886
+ dark: "color.black.a50"
887
+ },
888
+ shadow: {
889
+ light: "color.black.a10",
890
+ dark: "color.black.a50"
891
+ },
892
+ "effect.shadow.card.color": {
893
+ light: "color.black.a10",
894
+ dark: "color.black.a50"
895
+ },
896
+ "effect.shadow.floating.color": {
897
+ light: "color.black.a10",
898
+ dark: "color.black.a50"
899
+ },
900
+ "effect.shadow.dialog.color": {
901
+ light: "color.black.a10",
902
+ dark: "color.black.a50"
731
903
  }
732
904
  };
733
905
  //#endregion
@@ -828,11 +1000,11 @@ const cubicBezier = z.tuple([
828
1000
  const fontStack = z.array(z.string()).min(1);
829
1001
  const colorSeedShape = Object.fromEntries(T1_COLOR_KEYS.map((key) => [key, seedColor]));
830
1002
  /**
831
- * SeedSchema — T1 Seed 的唯一事实源校验(RFC 0001 §2.1,v3 修订)。
1003
+ * SeedSchema — T1 Seed 与兼容输入的运行时校验(RFC 0001 §2.1,v4 修订)。
832
1004
  *
833
1005
  * 五大类目 color/size/typography/motion/effect,字段结构对齐
834
- * packages/tokens/design/seed.tokens.json,全部字段必填——不允许省略后静默
835
- * 回退默认值,锚点缺口必须在 Seed 层显式补齐,Reference 层不得用硬编码兜底。
1006
+ * packages/tokens/design/seed.tokens.json。部分已不再驱动 canonical T2 的字段暂时
1007
+ * 保留为兼容输入;新 Reference 不得为了形式完整继续扩充伪 Seed。
836
1008
  *
837
1009
  * v3 变化:
838
1010
  * - 颜色全部结构化(DTCG Color module,支持 srgb/oklch)。
@@ -881,8 +1053,11 @@ base: z.string() }),
881
1053
  textWindowsJa: fontStack
882
1054
  }),
883
1055
  fontWeight: z.object({
1056
+ /** @deprecated T2 Font Weight 已是 standard-constant;保留到下一次 Seed API 主版本清理。 */
884
1057
  regular: z.number(),
1058
+ /** @deprecated T2 Font Weight 已是 standard-constant;保留到下一次 Seed API 主版本清理。 */
885
1059
  medium: z.number(),
1060
+ /** @deprecated T2 Font Weight 已是 standard-constant;保留到下一次 Seed API 主版本清理。 */
886
1061
  semibold: z.number()
887
1062
  }),
888
1063
  fontSize: z.object({ base: z.string() }),
@@ -1093,6 +1268,14 @@ function seedAlphaCss(seedColor, alpha) {
1093
1268
  });
1094
1269
  return rgba(hexRgb(seedColorToHex(seedColor)), alpha);
1095
1270
  }
1271
+ /** 从 Seed 颜色点分路径("color.brand")取 T1 键。 */
1272
+ function seedKeyOf(seedRef) {
1273
+ return seedRef.split(".")[1];
1274
+ }
1275
+ /** 步进锚定 Alpha 的求值:FIGMA_T2_SOLID_SCALE 档位实色 + alpha → rgba。 */
1276
+ function stepAlphaCss(seed, step, alpha) {
1277
+ return rgba(hexRgb(FIGMA_T2_SOLID_SCALE[seed][step]), alpha);
1278
+ }
1096
1279
  function formatFontFamily(list) {
1097
1280
  return list.map((f) => /[\s./]/.test(f) ? `'${f}'` : f).join(", ");
1098
1281
  }
@@ -1154,6 +1337,7 @@ function evaluateDerivation(d, seed) {
1154
1337
  case "oklchRamp": return ramp(seed.color[d.seedRef.split(".")[1]])[d.step];
1155
1338
  case "figmaOklchScale": return d.value;
1156
1339
  case "seedAlpha": return seedAlphaCss(seedValueAt(seed, d.seedRef), d.alpha);
1340
+ case "stepAlpha": return stepAlphaCss(seedKeyOf(d.seedRef), d.step, d.alpha);
1157
1341
  case "alphaScale": {
1158
1342
  const step = seedValueAt(seed, d.stepRef);
1159
1343
  return rgba(d.channel === "black" ? [
@@ -1168,7 +1352,7 @@ function evaluateDerivation(d, seed) {
1168
1352
  }
1169
1353
  case "fontStack": return formatFontFamily(seedValueAt(seed, d.seedRef));
1170
1354
  case "cubicBezier": return formatCubicBezier(seedValueAt(seed, d.seedRef));
1171
- case "literal": return d.value;
1355
+ case "literal": return String(d.value);
1172
1356
  case "shadowLayer": {
1173
1357
  const { offsetX, offsetY, blur, spread } = shadowShapeOf(seed, d.level);
1174
1358
  return `${offsetX} ${offsetY} ${blur} ${spread} ${rgba([
@@ -1189,6 +1373,7 @@ function seedRefsOf(d) {
1189
1373
  case "oklchRamp":
1190
1374
  case "figmaOklchScale":
1191
1375
  case "seedAlpha":
1376
+ case "stepAlpha":
1192
1377
  case "fontStack":
1193
1378
  case "cubicBezier": return [d.seedRef];
1194
1379
  case "offsetSteps": return [d.seedRef, d.stepRef];
@@ -1197,6 +1382,18 @@ function seedRefsOf(d) {
1197
1382
  case "shadowLayer": return ["effect.shadow.base", "size.opacity.alphaStep"];
1198
1383
  }
1199
1384
  }
1385
+ /** Derivation AST → 规范来源分类;作为 Figma/DTCG provenance 的唯一映射口。 */
1386
+ function sourceKindOf(d) {
1387
+ switch (d.kind) {
1388
+ case "alias":
1389
+ case "fontStack":
1390
+ case "cubicBezier": return "seed-alias";
1391
+ case "figmaOklchScale":
1392
+ case "stepAlpha": return "design-calibrated";
1393
+ case "literal": return "standard-constant";
1394
+ default: return "seed-derived";
1395
+ }
1396
+ }
1200
1397
  /** 人读派生公式(Token Studio 展示用)。 */
1201
1398
  function formatDerivation(d) {
1202
1399
  const sign = (n) => n >= 0 ? "+" : "−";
@@ -1210,20 +1407,24 @@ function formatDerivation(d) {
1210
1407
  case "offsetSteps": return `= seed.${d.seedRef} ${sign(d.n)} seed.${d.stepRef} × ${Math.abs(d.n)}`;
1211
1408
  case "oklchRamp": return `= oklch(seed.${d.seedRef}) @ L ${L_TARGETS[d.step]} · C × ${round2(chromaFactor(L_TARGETS[d.step]))}`;
1212
1409
  case "figmaOklchScale": return `= figma Color/qw/t2/${d.seedRef.split(".")[1]}/${d.step}(OKLCH 设计校准)`;
1410
+ case "stepAlpha": return `= figma Color/qw/t2/${d.seedRef.split(".")[1]}/${d.step}-a${round2(d.alpha * 100)}(步进锚定 Alpha)`;
1213
1411
  case "seedAlpha": return `= seed.${d.seedRef} / ${round2(d.alpha * 100)}%`;
1214
1412
  case "alphaScale": return `= ${d.channel === "black" ? "黑" : "白"} / seed.${d.stepRef} × ${d.multiplier}`;
1215
- case "literal": return `= ${d.value}(色彩空间端点,白名单字面量)`;
1413
+ case "literal": return `= ${d.value}(canonical 标准常量)`;
1216
1414
  case "shadowLayer": {
1217
1415
  const f = SHADOW_LEVELS[d.level];
1218
1416
  return `= seed.effect.shadow.base 形状 × {offset ${f.offset}, blur ${f.blur}} · 色 = 黑 / alphaStep × ${f.alphaMult}`;
1219
1417
  }
1220
1418
  }
1221
1419
  }
1222
- function ref(path, derivation) {
1420
+ function ref(path, derivation, metadata = {}) {
1421
+ const { sourceKind = sourceKindOf(derivation), ...details } = metadata;
1223
1422
  return {
1224
1423
  path,
1225
1424
  cssVar: toVar("ref", path),
1425
+ sourceKind,
1226
1426
  seedRefs: seedRefsOf(derivation),
1427
+ ...details,
1227
1428
  derivation
1228
1429
  };
1229
1430
  }
@@ -1251,6 +1452,9 @@ function buildColorRampRecipes() {
1251
1452
  seedRef,
1252
1453
  step,
1253
1454
  value: FIGMA_T2_SOLID_SCALE[name][step]
1455
+ }, {
1456
+ source: `Figma Color/qw/t2/${name}/${step}`,
1457
+ rationale: "OKLCH solid scale is design-calibrated; the Seed records color-family lineage, not the final step value."
1254
1458
  }));
1255
1459
  out.push(ref([
1256
1460
  "color",
@@ -1263,6 +1467,35 @@ function buildColorRampRecipes() {
1263
1467
  }
1264
1468
  return out;
1265
1469
  }
1470
+ /** 2. Figma T2 补充原语:步进锚定 Alpha(仅被 T3 消费的条目)+ black/pure 标准常量。 */
1471
+ function buildColorExtraRecipes() {
1472
+ const out = [];
1473
+ for (const { seed, step, alpha } of FIGMA_T2_STEP_ALPHA) out.push(ref([
1474
+ "color",
1475
+ seed,
1476
+ `${step}-a${alpha}`
1477
+ ], {
1478
+ kind: "stepAlpha",
1479
+ seedRef: `color.${seed}`,
1480
+ step,
1481
+ alpha: alpha / 100
1482
+ }, {
1483
+ source: `Figma Color/qw/t2/${seed}/${step}-a${alpha}`,
1484
+ rationale: "Step-anchored alpha is design-calibrated: both the anchored solid step and the alpha are pinned by the design file."
1485
+ }));
1486
+ out.push(ref([
1487
+ "color",
1488
+ "black",
1489
+ "pure"
1490
+ ], {
1491
+ kind: "literal",
1492
+ value: "#000000"
1493
+ }, {
1494
+ source: "CSS Color sRGB endpoint",
1495
+ rationale: "Mathematical black endpoint for OLED canvas; replaces deprecated neutral/1000 semantics; no theme-level generator input."
1496
+ }));
1497
+ return out;
1498
+ }
1266
1499
  /** 4. 间距刻度 = spacing.step × N (N=1..8)。 */
1267
1500
  function buildSpacingRecipes() {
1268
1501
  const out = [];
@@ -1277,13 +1510,14 @@ function buildSpacingRecipes() {
1277
1510
  }));
1278
1511
  return out;
1279
1512
  }
1280
- /** 圆角档位系数(sm/lg 从 base 派生;默认 base=8px → 4/8/14)。 */
1513
+ /** 圆角档位系数(sm/lg/xl 从 base 派生;默认 base=8px → 4/8/14/16)。 */
1281
1514
  const RADIUS_FACTORS = {
1282
1515
  sm: .5,
1283
1516
  md: 1,
1284
- lg: 1.75
1517
+ lg: 1.75,
1518
+ xl: 2
1285
1519
  };
1286
- /** 5. 圆角刻度:sm/md/lg 由 radius.base 按系数派生,full 直通独立裁切基准。 */
1520
+ /** 5. 圆角刻度:sm/md/lg/xl 由 radius.base 按系数派生,full 直通独立裁切基准。xl=2×base 对齐治理稿 Radius v2 的 T2 double。 */
1287
1521
  function buildRadiusRecipes() {
1288
1522
  return [
1289
1523
  ref([
@@ -1312,6 +1546,15 @@ function buildRadiusRecipes() {
1312
1546
  seedRef: "size.radius.base",
1313
1547
  factor: RADIUS_FACTORS.lg
1314
1548
  }),
1549
+ ref([
1550
+ "size",
1551
+ "radius",
1552
+ "xl"
1553
+ ], {
1554
+ kind: "scale",
1555
+ seedRef: "size.radius.base",
1556
+ factor: RADIUS_FACTORS.xl
1557
+ }),
1315
1558
  ref([
1316
1559
  "size",
1317
1560
  "radius",
@@ -1384,16 +1627,108 @@ function buildControlIconSizeRecipes() {
1384
1627
  })
1385
1628
  ];
1386
1629
  }
1387
- /** 7. 描边宽度 —— 直通引用。 */
1388
- function buildBorderWidthRecipes() {
1389
- return [ref([
1630
+ /** 描边宽度梯度系数(Figma Stroke v1:Half/Base/Double/Triple = 0.5/1/2/3)。 */
1631
+ const STROKE_WIDTH_FACTORS = {
1632
+ half: .5,
1633
+ double: 2,
1634
+ triple: 3
1635
+ };
1636
+ /** 7. 描边宽度(Figma Stroke v1):base 直通 Seed,half/double/triple 按系数派生。 */
1637
+ function buildStrokeWidthRecipes() {
1638
+ const seedRef = "size.borderWidth.hairline";
1639
+ return [
1640
+ ref([
1641
+ "size",
1642
+ "strokeWidth",
1643
+ "half"
1644
+ ], {
1645
+ kind: "scale",
1646
+ seedRef,
1647
+ factor: STROKE_WIDTH_FACTORS.half
1648
+ }),
1649
+ ref([
1650
+ "size",
1651
+ "strokeWidth",
1652
+ "base"
1653
+ ], {
1654
+ kind: "alias",
1655
+ seedRef
1656
+ }),
1657
+ ref([
1658
+ "size",
1659
+ "strokeWidth",
1660
+ "double"
1661
+ ], {
1662
+ kind: "scale",
1663
+ seedRef,
1664
+ factor: STROKE_WIDTH_FACTORS.double
1665
+ }),
1666
+ ref([
1667
+ "size",
1668
+ "strokeWidth",
1669
+ "triple"
1670
+ ], {
1671
+ kind: "scale",
1672
+ seedRef,
1673
+ factor: STROKE_WIDTH_FACTORS.triple
1674
+ })
1675
+ ];
1676
+ }
1677
+ /** 六档动作控件高度(Figma Action Control v1):现有公开尺寸契约,不能由单一 T1 Base 可靠派生,直接定义在 T2(T1 不设 Control Size)。 */
1678
+ const ACTION_CONTROL_HEIGHTS = {
1679
+ "2xs": 24,
1680
+ xs: 28,
1681
+ sm: 32,
1682
+ md: 36,
1683
+ lg: 42,
1684
+ xl: 50
1685
+ };
1686
+ /** 7b. 动作控件尺寸:六档高度 + 2XS 图标特例(Square 复用同档 Height,不另设 token)。 */
1687
+ function buildActionControlRecipes() {
1688
+ const out = [];
1689
+ for (const [step, value] of Object.entries(ACTION_CONTROL_HEIGHTS)) out.push(ref([
1390
1690
  "size",
1391
- "borderWidth",
1392
- "hairline"
1691
+ "actionControlHeight",
1692
+ step
1393
1693
  ], {
1394
- kind: "alias",
1395
- seedRef: "size.borderWidth.hairline"
1396
- })];
1694
+ kind: "literal",
1695
+ value: `${value}px`
1696
+ }, {
1697
+ source: "Figma 千问三方——Token 改造 · Foundation/Action Control Standard v1",
1698
+ rationale: "六档高度 24/28/32/36/42/50 是现有公开尺寸契约,治理稿将其直接定义在 T2,T1 不设置 Control Size。"
1699
+ }));
1700
+ out.push(ref([
1701
+ "size",
1702
+ "actionControlIcon",
1703
+ "2xs"
1704
+ ], {
1705
+ kind: "literal",
1706
+ value: "14px"
1707
+ }, {
1708
+ source: "Figma 千问三方——Token 改造 · Foundation/Action Control Standard v1",
1709
+ rationale: "2XS 图标 14px 是治理稿已标记的组件特例(不扩充全局 Icon Scale);视觉验证通过后优先归一化为 Icon Size/Small。"
1710
+ }));
1711
+ return out;
1712
+ }
1713
+ /** Avatar 三档直径(Figma 头像 · Avatar S/M/L = 40/50/58)。 */
1714
+ const AVATAR_DIAMETERS = {
1715
+ sm: 40,
1716
+ md: 50,
1717
+ lg: 58
1718
+ };
1719
+ /** 7c. 展示类专用尺寸:Avatar 直径(Icon Size 规范要求 Avatar 直径使用自己的语义,禁止借用 Icon/Control 刻度)。 */
1720
+ function buildAvatarDiameterRecipes() {
1721
+ return Object.entries(AVATAR_DIAMETERS).map(([step, value]) => ref([
1722
+ "size",
1723
+ "avatarDiameter",
1724
+ step
1725
+ ], {
1726
+ kind: "literal",
1727
+ value: `${value}px`
1728
+ }, {
1729
+ source: "Figma 千问三方——Token 改造 · 头像 · Avatar(S/M/L)",
1730
+ rationale: "Avatar 直径 40/50/58 是展示类专用尺寸契约;Icon Size 规范明确 Avatar 直径必须使用各自语义,不由 T1 派生。"
1731
+ }));
1397
1732
  }
1398
1733
  /** 8. 行高(typography 类目):normal 直通 Seed,tight/relaxed = base ∓ 0.25。 */
1399
1734
  function buildLineHeightRecipes() {
@@ -1465,14 +1800,15 @@ const FONT_FAMILY_KEYS = [
1465
1800
  "textWindowsZh",
1466
1801
  "textWindowsJa"
1467
1802
  ];
1468
- /** 字号档位倍数(沿用既定视觉:14px 基准 → 12/16/20/24)。 */
1803
+ /** 字号档位倍数(沿用既定视觉:14px 基准 → 11/12/16/20/24;xs=11 对齐治理稿 T2 Font Size 2XS)。 */
1469
1804
  const FONT_SIZE_FACTORS = {
1805
+ xs: .786,
1470
1806
  sm: .857,
1471
1807
  lg: 1.143,
1472
1808
  xl: 1.429,
1473
1809
  "2xl": 1.714
1474
1810
  };
1475
- /** 11. 排版原子:字体族(三族 + 平台/语言变体)/字重直通,字号按既定倍数派生。 */
1811
+ /** 11. 排版原子:字体族来自平台 Seed;字重是机械标准常量;字号按既定倍数派生。 */
1476
1812
  function buildTypographyRecipes() {
1477
1813
  const out = [];
1478
1814
  for (const key of FONT_FAMILY_KEYS) out.push(ref([
@@ -1483,17 +1819,20 @@ function buildTypographyRecipes() {
1483
1819
  kind: "fontStack",
1484
1820
  seedRef: `typography.fontFamily.${key}`
1485
1821
  }));
1486
- for (const key of [
1487
- "regular",
1488
- "medium",
1489
- "semibold"
1822
+ for (const [key, value] of [
1823
+ ["regular", 400],
1824
+ ["medium", 500],
1825
+ ["semibold", 600]
1490
1826
  ]) out.push(ref([
1491
1827
  "typography",
1492
1828
  "fontWeight",
1493
1829
  key
1494
1830
  ], {
1495
- kind: "alias",
1496
- seedRef: `typography.fontWeight.${key}`
1831
+ kind: "literal",
1832
+ value
1833
+ }, {
1834
+ source: "CSS Fonts numeric font-weight scale",
1835
+ rationale: "Mechanical weight step; changing it is a semantic typography decision, not a global generator input."
1497
1836
  }));
1498
1837
  out.push(ref([
1499
1838
  "typography",
@@ -1588,10 +1927,13 @@ function buildShadowRecipes() {
1588
1927
  function allReferenceRecipes() {
1589
1928
  return [
1590
1929
  ...buildColorRampRecipes(),
1930
+ ...buildColorExtraRecipes(),
1591
1931
  ...buildSpacingRecipes(),
1592
1932
  ...buildRadiusRecipes(),
1593
1933
  ...buildControlIconSizeRecipes(),
1594
- ...buildBorderWidthRecipes(),
1934
+ ...buildStrokeWidthRecipes(),
1935
+ ...buildActionControlRecipes(),
1936
+ ...buildAvatarDiameterRecipes(),
1595
1937
  ...buildLineHeightRecipes(),
1596
1938
  ...buildOpacityRecipes(),
1597
1939
  ...buildZIndexRecipes(),
@@ -1626,8 +1968,10 @@ function semVar(path) {
1626
1968
  return toVar("sem", path);
1627
1969
  }
1628
1970
  const RADIUS_ROLES = {
1971
+ sm: "size.radius.sm",
1629
1972
  control: "size.radius.md",
1630
1973
  card: "size.radius.lg",
1974
+ xl: "size.radius.xl",
1631
1975
  pill: "size.radius.full",
1632
1976
  full: "size.radius.full"
1633
1977
  };
@@ -1641,6 +1985,57 @@ const ICON_SIZE_ROLES = {
1641
1985
  md: "size.iconSize.md",
1642
1986
  lg: "size.iconSize.lg"
1643
1987
  };
1988
+ const ACTION_CONTROL_HEIGHT_ROLES = {
1989
+ "2xs": "size.actionControlHeight.2xs",
1990
+ xs: "size.actionControlHeight.xs",
1991
+ sm: "size.actionControlHeight.sm",
1992
+ md: "size.actionControlHeight.md",
1993
+ lg: "size.actionControlHeight.lg",
1994
+ xl: "size.actionControlHeight.xl"
1995
+ };
1996
+ const ACTION_CONTROL_PADDING_INLINE_ROLES = {
1997
+ "2xs": "size.spacing.2",
1998
+ xs: "size.spacing.2",
1999
+ sm: "size.spacing.4",
2000
+ md: "size.spacing.4",
2001
+ lg: "size.spacing.5",
2002
+ xl: "size.spacing.8"
2003
+ };
2004
+ const ACTION_CONTROL_ICON_ROLES = {
2005
+ "2xs": "size.actionControlIcon.2xs",
2006
+ xs: "size.iconSize.sm",
2007
+ sm: "size.iconSize.sm",
2008
+ md: "size.iconSize.sm",
2009
+ lg: "size.iconSize.sm",
2010
+ xl: "size.iconSize.md"
2011
+ };
2012
+ const ACTION_CONTROL_GAP_ROLES = {
2013
+ "2xs": "size.spacing.1",
2014
+ xs: "size.spacing.1",
2015
+ sm: "size.spacing.2",
2016
+ md: "size.spacing.2",
2017
+ lg: "size.spacing.2",
2018
+ xl: "size.spacing.2"
2019
+ };
2020
+ const BORDER_WIDTH_ROLES = {
2021
+ default: "size.strokeWidth.base",
2022
+ strong: "size.strokeWidth.double"
2023
+ };
2024
+ const DIVIDER_WIDTH_ROLES = {
2025
+ thin: "size.strokeWidth.half",
2026
+ default: "size.strokeWidth.base"
2027
+ };
2028
+ const FOCUS_RING_ROLES = {
2029
+ width: "size.strokeWidth.double",
2030
+ offset: "size.strokeWidth.double"
2031
+ };
2032
+ const INDICATOR_ROLES = { loading: "size.strokeWidth.double" };
2033
+ /** 展示类专用尺寸:Avatar 直径三档(Figma 头像 S/M/L)。 */
2034
+ const AVATAR_DIAMETER_ROLES = {
2035
+ sm: "size.avatarDiameter.sm",
2036
+ md: "size.avatarDiameter.md",
2037
+ lg: "size.avatarDiameter.lg"
2038
+ };
1644
2039
  const INSET_STACK_ROLES = {
1645
2040
  sm: "size.spacing.2",
1646
2041
  md: "size.spacing.4",
@@ -1708,6 +2103,22 @@ const TYPOGRAPHY_ROLES = {
1708
2103
  lineHeightRef: "typography.lineHeight.normal",
1709
2104
  letterSpacingRef: T_LETTER
1710
2105
  },
2106
+ /** 大正文(治理稿 T3 字段「大正文 16px · T2 M」):行高沿用 canonical 比例引擎。 */
2107
+ bodyLg: {
2108
+ fontFamilyRef: "typography.fontFamily.text",
2109
+ fontSizeRef: "typography.fontSize.lg",
2110
+ fontWeightRef: "typography.fontWeight.regular",
2111
+ lineHeightRef: "typography.lineHeight.normal",
2112
+ letterSpacingRef: T_LETTER
2113
+ },
2114
+ /** 小标签(治理稿 Text/Label/Small = 11/500/16):字号取 T2 xs=11px。 */
2115
+ labelSm: {
2116
+ fontFamilyRef: "typography.fontFamily.text",
2117
+ fontSizeRef: "typography.fontSize.xs",
2118
+ fontWeightRef: "typography.fontWeight.medium",
2119
+ lineHeightRef: "typography.lineHeight.normal",
2120
+ letterSpacingRef: T_LETTER
2121
+ },
1711
2122
  code: {
1712
2123
  fontFamilyRef: "typography.fontFamily.code",
1713
2124
  fontSizeRef: "typography.fontSize.sm",
@@ -1716,15 +2127,22 @@ const TYPOGRAPHY_ROLES = {
1716
2127
  letterSpacingRef: T_LETTER
1717
2128
  }
1718
2129
  };
1719
- const COLOR_ROLES = {
1720
- ...FIGMA_T3_COLOR_ROLES,
1721
- shadow: {
1722
- light: "color.black.a10",
1723
- dark: "color.black.a50"
1724
- }
2130
+ /**
2131
+ * 颜色角色的 Semantic 变量路径:绝大多数角色落在 `--qw-sem-color-*` 下;
2132
+ * `effect.shadow.*.color` 是复合阴影的颜色分量,对应 Figma 变量
2133
+ * `--qw-sem-effect-shadow-*-color`,不带 `color-` 前缀。
2134
+ */
2135
+ function colorRoleSemPath(role) {
2136
+ const segs = role.split(".");
2137
+ return segs[0] === "effect" ? segs : ["color", ...segs];
2138
+ }
2139
+ const COLOR_ROLES = { ...FIGMA_T3_COLOR_ROLES };
2140
+ /** 复合阴影角色:形状取 Reference effect.shadow.<level>,颜色取各自的 effect.shadow.<role>.color 分量。 */
2141
+ const SHADOW_COMPOSITE_ROLES = {
2142
+ card: "sm",
2143
+ floating: "md",
2144
+ dialog: "lg"
1725
2145
  };
1726
- /** 复合阴影角色:形状取 Reference effect.shadow.<level>,颜色取 color.shadow。 */
1727
- const SHADOW_COMPOSITE_ROLES = { dialog: "lg" };
1728
2146
  /**
1729
2147
  * 全量 Semantic 角色的结构化血缘表——"角色 → 引用的 Reference 路径(含 light/dark 分支)"。
1730
2148
  * 与 buildSemanticStructural/buildSemanticColor 的产出一一对应(顺序一致)。
@@ -1752,6 +2170,51 @@ function semanticRoleEntries() {
1752
2170
  "iconSize",
1753
2171
  role
1754
2172
  ], refPath);
2173
+ for (const [role, refPath] of Object.entries(ACTION_CONTROL_HEIGHT_ROLES)) structural([
2174
+ "size",
2175
+ "actionControlHeight",
2176
+ role
2177
+ ], refPath);
2178
+ for (const [role, refPath] of Object.entries(ACTION_CONTROL_PADDING_INLINE_ROLES)) structural([
2179
+ "size",
2180
+ "actionControlPaddingInline",
2181
+ role
2182
+ ], refPath);
2183
+ for (const [role, refPath] of Object.entries(ACTION_CONTROL_ICON_ROLES)) structural([
2184
+ "size",
2185
+ "actionControlIcon",
2186
+ role
2187
+ ], refPath);
2188
+ for (const [role, refPath] of Object.entries(ACTION_CONTROL_GAP_ROLES)) structural([
2189
+ "size",
2190
+ "actionControlGap",
2191
+ role
2192
+ ], refPath);
2193
+ for (const [role, refPath] of Object.entries(BORDER_WIDTH_ROLES)) structural([
2194
+ "size",
2195
+ "borderWidth",
2196
+ role
2197
+ ], refPath);
2198
+ for (const [role, refPath] of Object.entries(DIVIDER_WIDTH_ROLES)) structural([
2199
+ "size",
2200
+ "dividerWidth",
2201
+ role
2202
+ ], refPath);
2203
+ for (const [role, refPath] of Object.entries(FOCUS_RING_ROLES)) structural([
2204
+ "size",
2205
+ "focusRing",
2206
+ role
2207
+ ], refPath);
2208
+ for (const [role, refPath] of Object.entries(INDICATOR_ROLES)) structural([
2209
+ "size",
2210
+ "indicator",
2211
+ role
2212
+ ], refPath);
2213
+ for (const [role, refPath] of Object.entries(AVATAR_DIAMETER_ROLES)) structural([
2214
+ "size",
2215
+ "avatarDiameter",
2216
+ role
2217
+ ], refPath);
1755
2218
  for (const [role, refPath] of Object.entries(INSET_STACK_ROLES)) {
1756
2219
  structural([
1757
2220
  "size",
@@ -1817,7 +2280,7 @@ function semanticRoleEntries() {
1817
2280
  "standard"
1818
2281
  ], "motion.easing.standard");
1819
2282
  for (const [path, refs] of Object.entries(COLOR_ROLES)) {
1820
- const segs = ["color", ...path.split(".")];
2283
+ const segs = colorRoleSemPath(path);
1821
2284
  out.push({
1822
2285
  kind: "color",
1823
2286
  path: segs.join("."),
@@ -1836,7 +2299,7 @@ function semanticRoleEntries() {
1836
2299
  path: segs.join("."),
1837
2300
  cssVar: semVar(segs),
1838
2301
  shapeRef: `effect.shadow.${level}`,
1839
- colorRole: "color.shadow"
2302
+ colorRole: `effect.shadow.${role}.color`
1840
2303
  });
1841
2304
  }
1842
2305
  return out;
@@ -1864,9 +2327,9 @@ function buildSemanticColor(reference, mode) {
1864
2327
  if (entry.kind !== "color") continue;
1865
2328
  out[entry.cssVar] = pick(tokens, entry.refPath[mode]);
1866
2329
  }
1867
- const shadowColor = out[semVar(["color", "shadow"])];
1868
2330
  for (const [role, level] of Object.entries(SHADOW_COMPOSITE_ROLES)) {
1869
2331
  const shape = shapes.shadow[level];
2332
+ const shadowColor = out[semVar(colorRoleSemPath(`effect.shadow.${role}.color`))];
1870
2333
  out[semVar([
1871
2334
  "effect",
1872
2335
  "shadow",
@@ -1905,8 +2368,9 @@ function derive(seed) {
1905
2368
  *
1906
2369
  * 与静态 tokens.css(解析后的字面值,SSR 稳定出口)不同,live CSS 把整棵派生
1907
2370
  * 树翻译成 CSS 原生表达式:
1908
- * - T1 Seed 落为 `--qw-seed-*` 变量(唯一含具体数值的层);
1909
- * - T2 Reference 用 relative color(oklch(from …))/ calc() 从 Seed 变量派生;
2371
+ * - T1 Seed 落为 `--qw-seed-*` 变量,承载需要全局级联的生成参数;
2372
+ * - T2 Reference 的 seed-derived 项用 relative color / calc() 派生,
2373
+ * design-calibrated / standard-constant 项保留 canonical 直接值;
1910
2374
  * - T3 Semantic 全部是 `var(--qw-ref-*)` 别名;dark 模式只在暗色选择器下
1911
2375
  * 重映射 sem → 不同的 ref 档位。
1912
2376
  *
@@ -1914,11 +2378,11 @@ function derive(seed) {
1914
2378
  * 级联更新,零 JS 重算。依赖现代 CSS(relative color / round()),刻意不做
1915
2379
  * 老浏览器兼容——组件库消费方继续用静态 tokens.css。
1916
2380
  */
1917
- const round4 = (n) => Math.round(n * 1e4) / 1e4;
2381
+ const round4$1 = (n) => Math.round(n * 1e4) / 1e4;
1918
2382
  function seedVar(dotted) {
1919
2383
  return toVar("seed", dotted.split("."));
1920
2384
  }
1921
- /** Seed 拍平成 `--qw-seed-*` → CSS 值。live CSS 里唯一携带具体数值的层。 */
2385
+ /** Seed 拍平成 `--qw-seed-*` → CSS 值;T2 仍可包含校准值或标准常量。 */
1922
2386
  function seedCssVars(seed) {
1923
2387
  const out = {};
1924
2388
  for (const [name, value] of Object.entries(seed.color)) out[seedVar(`color.${name}`)] = seedColorToCss(value);
@@ -1932,9 +2396,6 @@ function seedCssVars(seed) {
1932
2396
  out[seedVar("size.opacity.alphaStep")] = String(seed.size.opacity.alphaStep);
1933
2397
  out[seedVar("size.zIndex.step")] = String(seed.size.zIndex.step);
1934
2398
  for (const key of FONT_FAMILY_KEYS) out[seedVar(`typography.fontFamily.${key}`)] = formatFontFamily(seed.typography.fontFamily[key]);
1935
- out[seedVar("typography.fontWeight.regular")] = String(seed.typography.fontWeight.regular);
1936
- out[seedVar("typography.fontWeight.medium")] = String(seed.typography.fontWeight.medium);
1937
- out[seedVar("typography.fontWeight.semibold")] = String(seed.typography.fontWeight.semibold);
1938
2399
  out[seedVar("typography.fontSize.base")] = seed.typography.fontSize.base;
1939
2400
  out[seedVar("typography.lineHeight.base")] = String(seed.typography.lineHeight.base);
1940
2401
  out[seedVar("typography.letterSpacing.base")] = seed.typography.letterSpacing.base;
@@ -1972,13 +2433,14 @@ function derivationToCssExpr(d) {
1972
2433
  case "offsetSteps": return `calc(var(${seedVar(d.seedRef)}) ${d.n >= 0 ? "+" : "-"} var(${seedVar(d.stepRef)}) * ${Math.abs(d.n)})`;
1973
2434
  case "oklchRamp": {
1974
2435
  const l = L_TARGETS[d.step];
1975
- const f = round4(chromaFactor(l));
2436
+ const f = round4$1(chromaFactor(l));
1976
2437
  return `oklch(from var(${seedVar(d.seedRef)}) ${l} calc(c * ${f}) h)`;
1977
2438
  }
1978
2439
  case "figmaOklchScale": return d.value;
1979
- case "seedAlpha": return `rgb(from var(${seedVar(d.seedRef)}) r g b / ${round4(d.alpha)})`;
2440
+ case "seedAlpha": return `rgb(from var(${seedVar(d.seedRef)}) r g b / ${round4$1(d.alpha)})`;
2441
+ case "stepAlpha": return stepAlphaCss(seedKeyOf(d.seedRef), d.step, d.alpha);
1980
2442
  case "alphaScale": return `rgb(${d.channel === "black" ? "0 0 0" : "255 255 255"} / calc(var(${seedVar(d.stepRef)}) * ${d.multiplier}))`;
1981
- case "literal": return d.value;
2443
+ case "literal": return String(d.value);
1982
2444
  case "shadowLayer": {
1983
2445
  const s = shadowShapeExprs(d.level);
1984
2446
  const alpha = `calc(var(${seedVar("size.opacity.alphaStep")}) * ${SHADOW_LEVELS[d.level].alphaMult})`;
@@ -2021,212 +2483,372 @@ function buildLiveCss(seed, options = {}) {
2021
2483
  ].join("\n");
2022
2484
  }
2023
2485
  //#endregion
2024
- //#region src/compat/schema.ts
2025
- /** DTCG 兼容的颜色字面量:hex、hex/NN% 透明度后缀,或结构化 srgb。 */
2026
- const legacyHexColor = z.string().regex(/^#[0-9A-Fa-f]{6}(\/\d{1,3}%)?$/, "期望 #RRGGBB 或 #RRGGBB/NN%");
2027
- const structuredColor = z.object({
2028
- colorSpace: z.literal("srgb"),
2029
- components: z.tuple([
2030
- z.number(),
2031
- z.number(),
2032
- z.number()
2033
- ]),
2034
- alpha: z.number().min(0).max(1)
2035
- });
2036
- const dimensionValue = z.object({
2037
- value: z.number(),
2038
- unit: z.enum([
2039
- "px",
2040
- "rem",
2041
- "em",
2042
- "%"
2043
- ])
2044
- });
2045
- const modePair = z.object({
2046
- light: z.union([
2047
- legacyHexColor,
2048
- structuredColor,
2049
- z.string()
2050
- ]),
2051
- dark: z.union([
2052
- legacyHexColor,
2053
- structuredColor,
2054
- z.string()
2055
- ])
2056
- });
2057
- const compatStatusSchema = z.enum([
2058
- "active",
2059
- "aliased",
2060
- "deprecated"
2061
- ]);
2062
- const compatEntrySchema = z.object({
2063
- path: z.string().regex(/^[a-z][a-z0-9-]*\.[a-z][a-z0-9.-]*$/, "path 格式:<component>.<category>.<name>,如 button.color.bg-soft-brand"),
2064
- type: z.enum([
2065
- "color",
2066
- "dimension",
2067
- "typography",
2068
- "motion"
2069
- ]),
2070
- value: z.union([
2071
- modePair,
2072
- dimensionValue,
2073
- z.object({ aliasOf: z.string().min(1) })
2074
- ]),
2075
- source: z.object({
2076
- figma: z.string().url(),
2077
- nodeId: z.string().min(1),
2078
- legacyName: z.string().nullable()
2079
- }),
2080
- introducedBy: z.string().min(1),
2081
- reason: z.string().min(1),
2082
- owner: z.string().min(1),
2083
- targetSemanticRole: z.string().nullable(),
2084
- status: compatStatusSchema,
2085
- reviewAfter: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
2086
- migrationIssue: z.string().nullable()
2087
- }).superRefine((entry, ctx) => {
2088
- if (entry.status === "aliased") {
2089
- if (!("aliasOf" in entry.value)) ctx.addIssue({
2090
- code: "custom",
2091
- message: "status=aliased 时 value 必须为 { aliasOf }",
2092
- path: ["value"]
2486
+ //#region src/figma/color-snapshot.ts
2487
+ /**
2488
+ * color-snapshot — 生成 Figma `Color` 变量集合的 DTCG 快照(design/color.tokens.json)。
2489
+ *
2490
+ * Figma 导出自动化通道尚未建立(变量 ID 本次不回填),快照由
2491
+ * color-architecture.ts 的同一份事实表投影生成,供 validate:figma-color 与
2492
+ * color-contract 测试消费;接上 Figma 导出后以导出物替换本生成物。
2493
+ */
2494
+ const NS$1 = "com.qianwen.qw-ui";
2495
+ const round4 = (n) => Math.round(n * 1e4) / 1e4;
2496
+ function hexComponents(hex) {
2497
+ const m = /^#?([0-9a-f]{6})$/i.exec(hex);
2498
+ if (!m) throw new Error(`[qw] invalid hex color: ${hex}`);
2499
+ const n = Number.parseInt(m[1], 16);
2500
+ return [
2501
+ round4((n >> 16 & 255) / 255),
2502
+ round4((n >> 8 & 255) / 255),
2503
+ round4((n & 255) / 255)
2504
+ ];
2505
+ }
2506
+ function colorValue(hex, alpha = 1) {
2507
+ return {
2508
+ colorSpace: "srgb",
2509
+ components: hexComponents(hex),
2510
+ alpha
2511
+ };
2512
+ }
2513
+ function t1Ref(seed) {
2514
+ return `{qw.t1.${seed}}`;
2515
+ }
2516
+ /** T3 角色引用的 T2 点分路径("color.blue.600-a20" → "qw.t2.blue.600-a20")。 */
2517
+ function t2Ref(dotted) {
2518
+ const [, seed, step] = dotted.split(".");
2519
+ return `{qw.t2.${seed}.${step}}`;
2520
+ }
2521
+ function t2Token(value, provenance) {
2522
+ return {
2523
+ $type: "color",
2524
+ $value: value,
2525
+ $extensions: { [NS$1]: { provenance } }
2526
+ };
2527
+ }
2528
+ function buildT1() {
2529
+ const t1 = {};
2530
+ for (const seed of T1_COLOR_KEYS) t1[seed] = {
2531
+ $type: "color",
2532
+ $value: colorValue(FIGMA_T1_SEED_HEX[seed])
2533
+ };
2534
+ return t1;
2535
+ }
2536
+ function buildT2() {
2537
+ const t2 = {};
2538
+ for (const seed of T1_COLOR_KEYS) {
2539
+ const seedHex = FIGMA_T1_SEED_HEX[seed];
2540
+ const steps = {};
2541
+ steps.base = t2Token(colorValue(seedHex), {
2542
+ sourceKind: "seed-alias",
2543
+ seedRefs: [t1Ref(seed)],
2544
+ formula: `= qw.t1.${seed}`
2093
2545
  });
2094
- if (!entry.targetSemanticRole) ctx.addIssue({
2095
- code: "custom",
2096
- message: "status=aliased 时 targetSemanticRole 必填",
2097
- path: ["targetSemanticRole"]
2546
+ for (const alpha of T2_ALPHA_STEPS) steps[`a${alpha}`] = t2Token(colorValue(seedHex, alpha / 100), {
2547
+ sourceKind: "seed-derived",
2548
+ seedRefs: [t1Ref(seed)],
2549
+ formula: `= qw.t1.${seed} / ${alpha}%`
2550
+ });
2551
+ for (const step of T2_OKLCH_STEPS) steps[String(step)] = t2Token(colorValue(FIGMA_T2_SOLID_SCALE[seed][step]), {
2552
+ sourceKind: "design-calibrated",
2553
+ seedRefs: [t1Ref(seed)],
2554
+ source: `Figma Color/qw/t2/${seed}/${step}`,
2555
+ formula: `= figma Color/qw/t2/${seed}/${step}(OKLCH 设计校准)`
2556
+ });
2557
+ for (const extra of FIGMA_T2_STEP_ALPHA) {
2558
+ if (extra.seed !== seed) continue;
2559
+ steps[`${extra.step}-a${extra.alpha}`] = t2Token(colorValue(FIGMA_T2_SOLID_SCALE[seed][extra.step], extra.alpha / 100), {
2560
+ sourceKind: "design-calibrated",
2561
+ seedRefs: [t1Ref(seed)],
2562
+ source: `Figma Color/qw/t2/${seed}/${extra.step}-a${extra.alpha}`,
2563
+ formula: `= figma Color/qw/t2/${seed}/${extra.step}-a${extra.alpha}(步进锚定 Alpha)`
2564
+ });
2565
+ }
2566
+ if (T2_PURE_SEEDS.includes(seed)) steps.pure = t2Token(colorValue("#000000"), {
2567
+ sourceKind: "standard-constant",
2568
+ seedRefs: [],
2569
+ source: "CSS Color sRGB endpoint",
2570
+ rationale: "Mathematical black endpoint for OLED canvas; no theme-level generator input.",
2571
+ formula: "= #000000(canonical 标准常量)"
2098
2572
  });
2573
+ t2[seed] = steps;
2099
2574
  }
2100
- if (entry.status === "active" && "aliasOf" in entry.value) ctx.addIssue({
2101
- code: "custom",
2102
- message: "status=active 时不得使用 aliasOf",
2103
- path: ["value"]
2104
- });
2105
- });
2106
- const compatRegistrySchema = z.object({
2107
- $description: z.string().optional(),
2108
- version: z.literal(1),
2109
- graceDays: z.number().int().positive().default(90),
2110
- entries: z.array(compatEntrySchema).min(1)
2111
- });
2112
- /** path → CSS 变量名:`button.color.bg-soft-brand` → `--qw-compat-button-color-bg-soft-brand` */
2113
- function compatPathToCssVar(path) {
2114
- return `--qw-compat-${path.replace(/\./g, "-")}`;
2575
+ return t2;
2115
2576
  }
2116
- /** path → component slug(第一段) */
2117
- function compatComponentOf(path) {
2118
- return path.split(".")[0];
2577
+ function buildT3() {
2578
+ const t3 = {};
2579
+ for (const [role, refs] of Object.entries(FIGMA_T3_COLOR_ROLES)) {
2580
+ const segs = role.split(".");
2581
+ const node = {
2582
+ $type: "color",
2583
+ $value: t2Ref(refs.light),
2584
+ $extensions: { [NS$1]: {
2585
+ cssVar: toVar("sem", colorRoleSemPath(role)),
2586
+ modes: {
2587
+ light: t2Ref(refs.light),
2588
+ dark: t2Ref(refs.dark)
2589
+ }
2590
+ } }
2591
+ };
2592
+ let cur = t3;
2593
+ for (let i = 0; i < segs.length - 1; i++) {
2594
+ const seg = segs[i];
2595
+ if (!(seg in cur)) cur[seg] = {};
2596
+ cur = cur[seg];
2597
+ }
2598
+ cur[segs[segs.length - 1]] = node;
2599
+ }
2600
+ return t3;
2119
2601
  }
2120
- /** path → helper suffix(component 之后的段,用 `-` 连接) */
2121
- function compatSuffixOf(path) {
2122
- return path.split(".").slice(1).join("-");
2602
+ /** 生成 design/color.tokens.json 的完整 JSON 对象(qw/t1/t2/t3 结构)。 */
2603
+ function buildFigmaColorSnapshot() {
2604
+ return {
2605
+ $schema: "https://www.designtokens.org/schemas/2025.10/format.json",
2606
+ $description: "qw-ui Color 变量集合快照(Figma 节点 22258:49986)。Figma 导出自动化通道建立前,由 scripts/export-design-tokens.ts 从 color-architecture.ts 同一份事实表投影生成,请勿手改;接上 Figma 导出后以导出物替换。校验:pnpm --filter @qw-ui/tokens validate:figma-color。",
2607
+ $extensions: { [NS$1]: {
2608
+ collection: "Color",
2609
+ figmaNode: "22258:49986",
2610
+ generated: true,
2611
+ owner: "design-system"
2612
+ } },
2613
+ qw: {
2614
+ t1: buildT1(),
2615
+ t2: buildT2(),
2616
+ t3: buildT3()
2617
+ }
2618
+ };
2123
2619
  }
2124
2620
  //#endregion
2125
- //#region src/compat/color.ts
2126
- /**
2127
- * 将 legacy hex(含 /NN% 透明度后缀)或 DTCG srgb 结构转为 CSS 颜色字符串。
2128
- */
2129
- function compatColorToCss(input) {
2130
- if (typeof input === "string") {
2131
- const m = /^#([0-9A-Fa-f]{6})(?:\/(\d{1,3})%)?$/.exec(input);
2132
- if (!m) throw new Error(`[qw-compat] 无法解析颜色: ${input}`);
2133
- const n = Number.parseInt(m[1], 16);
2134
- const r = n >> 16 & 255;
2135
- const g = n >> 8 & 255;
2136
- const b = n & 255;
2137
- const alpha = m[2] != null ? Number(m[2]) / 100 : 1;
2138
- if (alpha >= 1) return `#${m[1].toUpperCase()}`;
2139
- return `rgba(${r}, ${g}, ${b}, ${roundAlpha(alpha)})`;
2621
+ //#region src/figma/color-contract.ts
2622
+ const T2_OKLCH_STEP_KEYS = T2_OKLCH_STEPS.map(String);
2623
+ const NS = "com.qianwen.qw-ui";
2624
+ const T1_SET = new Set(T1_COLOR_KEYS);
2625
+ const T2_ALPHA_SET = new Set(T2_ALPHA_KEYS);
2626
+ const T2_OKLCH_SET = new Set(T2_OKLCH_STEP_KEYS);
2627
+ const T2_PURE_SEED_SET = new Set(T2_PURE_SEEDS);
2628
+ const T3_SEGMENT = /^[a-z]+(?:-[a-z]+)*$/;
2629
+ /** 步进锚定 Alpha 步名(如 "500-a20"):OKLCH 档位 + Alpha 档位两段。 */
2630
+ const T2_STEP_ALPHA_RE = /^(\d+)-a(\d+)$/;
2631
+ const PROVENANCE_SOURCE_KINDS = /* @__PURE__ */ new Set([
2632
+ "seed-alias",
2633
+ "seed-derived",
2634
+ "design-calibrated",
2635
+ "standard-constant",
2636
+ "external-standard"
2637
+ ]);
2638
+ const SEED_LINEAGE_KINDS = /* @__PURE__ */ new Set([
2639
+ "seed-alias",
2640
+ "seed-derived",
2641
+ "design-calibrated"
2642
+ ]);
2643
+ function isObject(value) {
2644
+ return value != null && typeof value === "object" && !Array.isArray(value);
2645
+ }
2646
+ function collectLeaves(node, path = [], out = []) {
2647
+ if (!isObject(node)) return out;
2648
+ if ("$value" in node) {
2649
+ out.push({
2650
+ path,
2651
+ value: node.$value,
2652
+ extensions: isObject(node.$extensions) ? node.$extensions : {}
2653
+ });
2654
+ return out;
2140
2655
  }
2141
- const [r, g, b] = input.components.map((c) => Math.round(c * 255));
2142
- const alpha = input.alpha;
2143
- if (alpha >= 1) return `#${[
2144
- r,
2145
- g,
2146
- b
2147
- ].map((x) => x.toString(16).padStart(2, "0")).join("")}`;
2148
- return `rgba(${r}, ${g}, ${b}, ${roundAlpha(alpha)})`;
2149
- }
2150
- function roundAlpha(a) {
2151
- return Math.round(a * 1e3) / 1e3;
2656
+ for (const [key, child] of Object.entries(node)) {
2657
+ if (key.startsWith("$")) continue;
2658
+ collectLeaves(child, [...path, key], out);
2659
+ }
2660
+ return out;
2152
2661
  }
2153
- //#endregion
2154
- //#region src/compat/build.ts
2155
- function dimensionToCss(value) {
2156
- return `${value.value}${value.unit}`;
2157
- }
2158
- function resolveEntryValue(entry, mode, semCssVar) {
2159
- const v = entry.value;
2160
- if ("aliasOf" in v) return `var(${semCssVar(v.aliasOf)})`;
2161
- if ("light" in v && "dark" in v) {
2162
- const raw = v[mode];
2163
- if (entry.type === "color") return compatColorToCss(raw);
2164
- return String(raw);
2662
+ function qwPath(path) {
2663
+ const index = path.indexOf("qw");
2664
+ return index >= 0 ? path.slice(index) : null;
2665
+ }
2666
+ function pathKey(path) {
2667
+ return path.join(".");
2668
+ }
2669
+ function refToPath(ref) {
2670
+ if (typeof ref !== "string") return null;
2671
+ const match = /^\{(.+)\}$/.exec(ref.trim());
2672
+ if (!match) return null;
2673
+ return match[1].split(/[./]/).filter(Boolean);
2674
+ }
2675
+ function extensionObject(leaf) {
2676
+ const ext = leaf.extensions[NS];
2677
+ return isObject(ext) ? ext : {};
2678
+ }
2679
+ function modesOf(leaf) {
2680
+ const ext = extensionObject(leaf);
2681
+ return isObject(ext.modes) ? ext.modes : {};
2682
+ }
2683
+ function provenanceOf(leaf) {
2684
+ const ext = extensionObject(leaf);
2685
+ return isObject(ext.provenance) ? ext.provenance : {};
2686
+ }
2687
+ function isSolidColorValue(value) {
2688
+ if (!isObject(value)) return false;
2689
+ if (value.colorSpace !== "srgb" && value.colorSpace !== "oklch") return false;
2690
+ if (!Array.isArray(value.components) || value.components.length !== 3) return false;
2691
+ return value.alpha === 1;
2692
+ }
2693
+ function isColorLikeValue(value) {
2694
+ if (!isObject(value)) return false;
2695
+ if (value.colorSpace !== "srgb" && value.colorSpace !== "oklch") return false;
2696
+ if (!Array.isArray(value.components) || value.components.length !== 3) return false;
2697
+ return typeof value.alpha === "number" && value.alpha >= 0 && value.alpha <= 1;
2698
+ }
2699
+ function validateNoUnexpectedName(path, errors) {
2700
+ const joined = pathKey(path);
2701
+ if (joined.includes("_")) errors.push(`${joined}: token name must not contain underscores`);
2702
+ if (path.some((segment) => /[A-Z]/.test(segment))) errors.push(`${joined}: token name must be lowercase`);
2703
+ }
2704
+ function validateT3Path(path, errors) {
2705
+ const joined = pathKey(path);
2706
+ 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`);
2707
+ }
2708
+ /** T2 步名分类:base / alpha / oklch / step-alpha / pure。 */
2709
+ function classifyT2Step(step) {
2710
+ if (step === "base") return "base";
2711
+ if (T2_ALPHA_SET.has(step)) return "alpha";
2712
+ if (T2_OKLCH_SET.has(step)) return "oklch";
2713
+ if (step === "pure") return "pure";
2714
+ const match = T2_STEP_ALPHA_RE.exec(step);
2715
+ if (match && T2_OKLCH_SET.has(match[1]) && T2_ALPHA_SET.has(`a${match[2]}`)) return "step-alpha";
2716
+ return null;
2717
+ }
2718
+ /** 各 T2 步类对应的 provenance.sourceKind(血缘治理不变量)。 */
2719
+ const T2_STEP_SOURCE_KIND = {
2720
+ base: "seed-alias",
2721
+ alpha: "seed-derived",
2722
+ oklch: "design-calibrated",
2723
+ "step-alpha": "design-calibrated",
2724
+ pure: "standard-constant"
2725
+ };
2726
+ function validateT2Provenance(leaf, seed, step, errors) {
2727
+ const joined = pathKey(leaf.path);
2728
+ const provenance = provenanceOf(leaf);
2729
+ if (Object.keys(provenance).length === 0) {
2730
+ errors.push(`${joined}: T2 token must declare $extensions.${NS}.provenance`);
2731
+ return;
2165
2732
  }
2166
- if ("value" in v && "unit" in v) return dimensionToCss(v);
2167
- throw new Error(`[qw-compat] 条目 ${entry.path} 的 value 形状无法解析`);
2168
- }
2169
- /** semantic role 点分路径 → --qw-sem-* CSS 变量 */
2170
- function semRoleToCssVar(role) {
2171
- const parts = role.split(".");
2172
- return `--qw-sem-${parts[0]}-${parts.slice(1).join("-")}`;
2173
- }
2174
- function buildCompatFromRegistry(registry) {
2175
- const light = {};
2176
- const dark = {};
2177
- const paths = {};
2178
- const byComponent = {};
2179
- for (const entry of registry.entries) {
2180
- const cssVar = compatPathToCssVar(entry.path);
2181
- paths[entry.path] = cssVar;
2182
- const component = compatComponentOf(entry.path);
2183
- const suffix = compatSuffixOf(entry.path);
2184
- if (!byComponent[component]) byComponent[component] = [];
2185
- byComponent[component].push(suffix);
2186
- const resolve = (mode) => resolveEntryValue(entry, mode, semRoleToCssVar);
2187
- if ("light" in entry.value && "dark" in entry.value) {
2188
- light[cssVar] = resolve("light");
2189
- const darkVal = resolve("dark");
2190
- if (darkVal !== light[cssVar]) dark[cssVar] = darkVal;
2191
- } else light[cssVar] = resolve("light");
2733
+ const { sourceKind, seedRefs } = provenance;
2734
+ if (typeof sourceKind !== "string" || !PROVENANCE_SOURCE_KINDS.has(sourceKind)) {
2735
+ errors.push(`${joined}: provenance.sourceKind must be one of ${[...PROVENANCE_SOURCE_KINDS].join(", ")}`);
2736
+ return;
2192
2737
  }
2193
- return {
2194
- light,
2195
- dark,
2196
- paths,
2197
- byComponent,
2198
- entries: registry.entries,
2199
- graceDays: registry.graceDays
2200
- };
2738
+ const stepKind = classifyT2Step(step);
2739
+ if (stepKind && T2_STEP_SOURCE_KIND[stepKind] !== sourceKind) errors.push(`${joined}: T2 ${stepKind} token must declare provenance.sourceKind = "${T2_STEP_SOURCE_KIND[stepKind]}"`);
2740
+ if (SEED_LINEAGE_KINDS.has(sourceKind)) {
2741
+ const expected = `{qw.t1.${seed}}`;
2742
+ if (!Array.isArray(seedRefs) || seedRefs.length !== 1 || seedRefs[0] !== expected) errors.push(`${joined}: provenance.seedRefs must be exactly ["${expected}"]`);
2743
+ return;
2744
+ }
2745
+ if (Array.isArray(seedRefs) && seedRefs.length > 0) errors.push(`${joined}: provenance.sourceKind "${sourceKind}" must not fabricate Seed lineage`);
2746
+ if (typeof provenance.source !== "string" || provenance.source.length === 0) errors.push(`${joined}: provenance.sourceKind "${sourceKind}" must declare provenance.source`);
2747
+ if (typeof provenance.rationale !== "string" || provenance.rationale.length === 0) errors.push(`${joined}: provenance.sourceKind "${sourceKind}" must declare provenance.rationale`);
2201
2748
  }
2202
- function componentSuffixTypeName(component) {
2203
- return `Compat${component.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")}Suffix`;
2204
- }
2205
- function componentSuffixConstName(component) {
2206
- return `compat${component.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")}Suffixes`;
2207
- }
2208
- /** 生成 compat token-paths TypeScript 片段(并入 tokens.ts) */
2209
- function formatCompatTypes(build) {
2210
- const components = Object.keys(build.byComponent).sort();
2211
- const lines = ["export const compatComponents = " + JSON.stringify(components) + " as const;", "export type CompatComponent = (typeof compatComponents)[number];"];
2212
- for (const c of components) {
2213
- const suffixes = [...build.byComponent[c]].sort();
2214
- const constName = componentSuffixConstName(c);
2215
- const typeName = componentSuffixTypeName(c);
2216
- lines.push(`export const ${constName} = ${JSON.stringify(suffixes)} as const;`);
2217
- lines.push(`export type ${typeName} = (typeof ${constName})[number];`);
2749
+ /** T3 角色全集(qw 路径),由 FIGMA_T3_COLOR_ROLES 投影。 */
2750
+ function figmaT3RolePaths() {
2751
+ return Object.keys(FIGMA_T3_COLOR_ROLES).map((role) => pathKey([
2752
+ "qw",
2753
+ "t3",
2754
+ ...role.split(".")
2755
+ ]));
2756
+ }
2757
+ function validateFigmaColorTokens(doc) {
2758
+ const errors = [];
2759
+ const leaves = collectLeaves(doc).map((leaf) => ({
2760
+ ...leaf,
2761
+ qwPath: qwPath(leaf.path)
2762
+ })).filter((leaf) => leaf.qwPath != null);
2763
+ const byQwPath = /* @__PURE__ */ new Map();
2764
+ for (const leaf of leaves) {
2765
+ const key = pathKey(leaf.qwPath);
2766
+ if (byQwPath.has(key)) errors.push(`${key}: duplicated token path`);
2767
+ byQwPath.set(key, leaf);
2768
+ validateNoUnexpectedName(leaf.qwPath, errors);
2218
2769
  }
2219
- if (components.length === 1) {
2220
- const c = components[0];
2221
- lines.push(`export type CompatSuffix<C extends CompatComponent> = C extends ${JSON.stringify(c)} ? ${componentSuffixTypeName(c)} : never;`);
2222
- } else if (components.length > 1) {
2223
- lines.push("export type CompatSuffix<C extends CompatComponent> =");
2224
- for (const c of components) lines.push(` C extends ${JSON.stringify(c)} ? ${componentSuffixTypeName(c)} :`);
2225
- lines.push(" never;");
2770
+ const t1 = leaves.filter((leaf) => leaf.qwPath[1] === "t1");
2771
+ const t2 = leaves.filter((leaf) => leaf.qwPath[1] === "t2");
2772
+ const t3 = leaves.filter((leaf) => leaf.qwPath[1] === "t3");
2773
+ const unknownLayers = leaves.filter((leaf) => ![
2774
+ "t1",
2775
+ "t2",
2776
+ "t3"
2777
+ ].includes(leaf.qwPath[1] ?? ""));
2778
+ for (const leaf of unknownLayers) errors.push(`${pathKey(leaf.qwPath)}: unknown Color token layer`);
2779
+ const t1Keys = /* @__PURE__ */ new Set();
2780
+ for (const leaf of t1) {
2781
+ const [, , key, ...rest] = leaf.qwPath;
2782
+ const joined = pathKey(leaf.qwPath);
2783
+ if (rest.length > 0 || !key) errors.push(`${joined}: T1 token must be qw/t1/{seed}`);
2784
+ if (key && !T1_SET.has(key)) errors.push(`${joined}: unexpected T1 seed "${key}"`);
2785
+ if (!isSolidColorValue(leaf.value)) errors.push(`${joined}: T1 seed must be a solid color with alpha = 1`);
2786
+ if (key) t1Keys.add(key);
2226
2787
  }
2227
- return lines.join("\n");
2788
+ const missingT1 = T1_COLOR_KEYS.filter((key) => !t1Keys.has(key));
2789
+ const extraT1 = [...t1Keys].filter((key) => !T1_SET.has(key));
2790
+ if (missingT1.length) errors.push(`qw.t1: missing required seeds ${missingT1.join(", ")}`);
2791
+ if (extraT1.length) errors.push(`qw.t1: unexpected seeds ${extraT1.join(", ")}`);
2792
+ const t2BySeed = /* @__PURE__ */ new Map();
2793
+ for (const seed of T1_COLOR_KEYS) t2BySeed.set(seed, /* @__PURE__ */ new Set());
2794
+ for (const leaf of t2) {
2795
+ const [, , seed, step, ...rest] = leaf.qwPath;
2796
+ const joined = pathKey(leaf.qwPath);
2797
+ if (rest.length > 0 || !seed || !step) errors.push(`${joined}: T2 token must be qw/t2/{seed}/{base|alpha|oklch-step}`);
2798
+ if (seed && !T1_SET.has(seed)) errors.push(`${joined}: T2 seed "${seed}" must exist in T1`);
2799
+ const stepKind = step ? classifyT2Step(step) : null;
2800
+ if (step && !stepKind) errors.push(`${joined}: unsupported T2 step "${step}"`);
2801
+ if (stepKind === "pure" && seed && !T2_PURE_SEED_SET.has(seed)) errors.push(`${joined}: "pure" step is only provided for seeds ${[...T2_PURE_SEED_SET].join(", ")}`);
2802
+ if (!isColorLikeValue(leaf.value) && step !== "base") errors.push(`${joined}: T2 token must carry a concrete color value`);
2803
+ if (seed && step && T1_SET.has(seed) && stepKind) {
2804
+ t2BySeed.get(seed).add(step);
2805
+ validateT2Provenance(leaf, seed, step, errors);
2806
+ }
2807
+ }
2808
+ for (const seed of T1_COLOR_KEYS) {
2809
+ const steps = t2BySeed.get(seed);
2810
+ const missingAlpha = T2_ALPHA_KEYS.filter((step) => !steps.has(step));
2811
+ const missingOklch = T2_OKLCH_STEP_KEYS.filter((step) => !steps.has(step));
2812
+ const unexpected = [...steps].filter((step) => !classifyT2Step(step));
2813
+ if (!steps.has("base")) errors.push(`qw.t2.${seed}: missing base token`);
2814
+ if (missingAlpha.length) errors.push(`qw.t2.${seed}: missing alpha steps ${missingAlpha.join(", ")}`);
2815
+ if (missingOklch.length) errors.push(`qw.t2.${seed}: missing OKLCH steps ${missingOklch.join(", ")}`);
2816
+ if (unexpected.length) errors.push(`qw.t2.${seed}: unexpected steps ${unexpected.join(", ")}`);
2817
+ }
2818
+ const expectedT3 = new Set(figmaT3RolePaths());
2819
+ const actualT3 = /* @__PURE__ */ new Set();
2820
+ for (const leaf of t3) {
2821
+ const joined = pathKey(leaf.qwPath);
2822
+ actualT3.add(joined);
2823
+ validateT3Path(leaf.qwPath, errors);
2824
+ if (!expectedT3.has(joined)) errors.push(`${joined}: unexpected T3 role (not in the 60-role Figma set)`);
2825
+ const modes = modesOf(leaf);
2826
+ const light = refToPath(modes.light);
2827
+ const dark = refToPath(modes.dark);
2828
+ if (!light || !dark) {
2829
+ errors.push(`${joined}: T3 token must declare both light and dark mode references`);
2830
+ continue;
2831
+ }
2832
+ for (const [modeName, ref] of [["light", light], ["dark", dark]]) if (ref[0] !== "qw" || ref[1] !== "t2") errors.push(`${joined}: ${modeName} mode must reference a T2 token`);
2833
+ else if (!byQwPath.has(pathKey(ref))) errors.push(`${joined}: ${modeName} mode references missing token {${pathKey(ref)}}`);
2834
+ }
2835
+ const missingT3 = [...expectedT3].filter((role) => !actualT3.has(role));
2836
+ if (missingT3.length) errors.push(`qw.t3: missing required roles ${missingT3.join(", ")}`);
2837
+ return {
2838
+ ok: errors.length === 0,
2839
+ errors,
2840
+ counts: {
2841
+ t1: t1.length,
2842
+ t2: t2.length,
2843
+ t3: t3.length
2844
+ }
2845
+ };
2846
+ }
2847
+ function assertFigmaColorTokens(doc) {
2848
+ const result = validateFigmaColorTokens(doc);
2849
+ if (!result.ok) throw new Error(`Invalid Figma Color tokens:\n${result.errors.map((error) => `- ${error}`).join("\n")}`);
2228
2850
  }
2229
2851
  //#endregion
2230
- export { COLOR_ROLES, FIGMA_COLOR_COLLECTION, FIGMA_COLOR_PREFIX, FIGMA_T1_SEED_HEX, FIGMA_T2_SOLID_SCALE, FIGMA_T3_COLOR_ROLES, L_TARGETS, RAMP_COLORS, SHADOW_COMPOSITE_ROLES, STEPS, SeedSchema, T1_COLOR_KEYS, T2_ALPHA_KEYS, T2_ALPHA_STEPS, T2_OKLCH_STEPS, TYPOGRAPHY_ROLES, allReferenceRecipes, buildCompatFromRegistry, buildLiveCss, buildReference, buildSemanticColor, buildSemanticStructural, compatPathToCssVar, compatRegistrySchema, contrastRatio, defaultSeed, derivationToCssExpr, derive, evaluateDerivation, formatCompatTypes, formatDerivation, hexToSeedColor, ramp, seedColorToCss, seedColorToHex, seedCssVars, seedRefsOf, seedValueAt, semanticRoleEntries, toVar, validateSeed };
2852
+ export { COLOR_ROLES, FIGMA_COLOR_COLLECTION, FIGMA_COLOR_PREFIX, FIGMA_T1_SEED_HEX, FIGMA_T2_SOLID_SCALE, FIGMA_T2_STEP_ALPHA, FIGMA_T3_COLOR_ROLES, L_TARGETS, RAMP_COLORS, SHADOW_COMPOSITE_ROLES, STEPS, SeedSchema, T1_COLOR_KEYS, T2_ALPHA_KEYS, T2_ALPHA_STEPS, T2_OKLCH_STEPS, T2_PURE_SEEDS, T2_PURE_STEP, TYPOGRAPHY_ROLES, allReferenceRecipes, assertFigmaColorTokens, buildFigmaColorSnapshot, buildLiveCss, buildReference, buildSemanticColor, buildSemanticStructural, contrastRatio, defaultSeed, derivationToCssExpr, derive, evaluateDerivation, figmaT3RolePaths, formatDerivation, hexToSeedColor, ramp, seedColorToCss, seedColorToHex, seedCssVars, seedRefsOf, seedValueAt, semanticRoleEntries, sourceKindOf, toVar, validateFigmaColorTokens, validateSeed };
2231
2853
 
2232
2854
  //# sourceMappingURL=index.js.map