@serenis / design-tokens
为Serenis设计系统设计令牌。生成类型化的JS常量、CSS自定义属性、cssvar访问器帮助器和CSS实用程序类——所有这些都来自一组 DTCG JSON文件。
看到 adr - 0011 用于架构决策。
安装
npm install @serenis/design-tokens
在你的应用入口点导入CSS包:
import '@serenis/design-tokens/css'
高级用例的子路径: @serenis/design-tokens/css/base, @serenis/design-tokens/css/design-tokens, @serenis/design-tokens/css/serenis-light, @serenis/design-tokens/css/serenis-dark, @serenis/design-tokens/css/global-style, @serenis/design-tokens/utilities.
快速启动
# Build all outputs (codegen + CSS + JS bundle)
yarn workspace @serenis/design-tokens build
# Run tests (includes golden snapshot tests)
yarn workspace @serenis/design-tokens test
# Update golden snapshots after intentional changes
yarn workspace @serenis/design-tokens test -- -u
目录结构
libraries/design-tokens/
├── tokens/ # DTCG JSON source files
│ ├── root.json # Base tokens (all types)
│ ├── serenis-light.json # Light theme overrides
│ ├── serenis-dark.json # Dark theme overrides
│ ├── aliases.json # Semantic alias tokens
│ └── md.json # Responsive overrides (≥601px)
├── src/
│ ├── global-style.css # Hand-written global reset + markdown semantic classes (→ dist/global-style.css)
│ ├── stories/ # Storybook stories and documentation (colocated)
│ │ ├── Breakpoints/
│ │ ├── Color/ # Color stories + Overview.mdx doc page
│ │ ├── Dimensions/
│ │ ├── Effects/
│ │ ├── Typography/
│ │ ├── UtilityClasses/
│ │ ├── components/ # Shared story helper components
│ │ └── docs/ # Domain-specific doc helpers for MDX pages
│ │ ├── components/ # Category-specific doc components (ColorPairing, etc.)
│ │ └── utils/ # Token description extractors (reads $description from JSON)
│ └── utils/ # Hand-written runtime helpers (compiled → dist/utils/)
├── scripts/
│ ├── pipeline/ # Build pipeline entry + Style Dictionary config
│ ├── codegen/ # TypeScript module generators
│ ├── cssUtilities/ # CSS utility class generator
│ └── shared/ # JSON reader, token key sorting
├── dist/ # Generated JS/DTS modules + CSS (gitignored)
│ ├── types/ # Token name arrays + union types
│ ├── constants/ # UPPER_SNAKE_CASE constants (var refs + raw values)
│ ├── cssvar/ # Typed accessor functions
│ ├── utils/ # Compiled from src/utils/
│ └── *.css # CSS custom properties + utility classes
└── package.json
文档页面
MDX文件 src/stories/ 被Storybook拾取为文档页(配置在 apps/design-system/.storybook/main.ts). 这些页面使用基于设计标记的排版 docs-reset.css,它覆盖了Storybook的内置样式。
可重用的文件页构建模块(SectionIntro, DosDonts, Table/Row, CodeExample)来自…… storybook-docs 图书馆。特定于类别的可视化组件(例如: ColorPairing) 住在 src/stories/docs/components/。令牌 $description 元数据由 src/stories/docs/utils/tokenDescriptions.ts,因此文档页面会自动与JSON源保持同步。
故事的排序顺序是“概述”页面放在首位,然后是“游乐场”,然后是其他页面。
撰写概述页面
每个令牌类别都应该有一个 Overview.mdx 遵循一致结构的文件。使用 Color/Overview.mdx 作为参考实现。
预期的部分:
- 标题+介绍 -类别名称为
# heading,那么,一行总结<SectionIntro>拉$description从令牌JSON源。 - 主题和响应行为 -这些令牌如何在主题和视图中表现。为了保持一致性,每个Overview页面都包含这个部分。
- 概念模型 -该类别中的令牌是如何组织的(层,尺度,命名逻辑)。使用
<Table>对于结构化的故障。 - 带代码示例的逐个令牌指南 -通过使用指南,渲染值浏览主要令牌/组,
<CodeExample>块,<DosDonts>。代码示例和指南在每个标记子节中交错,而不是在最后聚集。 - 可访问性/配对说明 (当相关时)-对比度,运动,大小,或其他对这一类别的考虑。并不是每个类别都需要一个专门的部分。
进口:
import { Meta } from '@storybook/addon-docs/blocks'
import { CodeExample, DosDonts, Row, SectionIntro, Table } from 'storybook-docs'
import { rootDescriptions } from '../docs'
// For themed tokens (Color, Effects):
import { rootDescriptions, lightDescriptions, darkDescriptions } from '../docs'
通用构件(SectionIntro, DosDonts, Table/Row, CodeExample)来自…… storybook-docs 图书馆。特定于类别的组件(例如: ColorPairing) 住在 src/stories/docs/components/。标记描述是预先计算的映射 src/stories/docs/utils/tokenDescriptions.ts ——使用 rootDescriptions.spacing, lightDescriptions.color等得到 $description 字符串。这使文档自动与JSON源同步。
如何消费
1. JS常量
对于必须存在于TypeScript中的值,比如第三方api:
import { COLOR_PRIMARY, SPACING_MD } from '@serenis/design-tokens'
const appearance = {
variables: { colorPrimary: COLOR_PRIMARY, spacingUnit: SPACING_MD },
}
每个常数解析为 var(--srns-spacing-md). 一个 _VALUE companion保存原始的CSS值:
SPACING_MD // "var(--srns-spacing-md)"
SPACING_MD_VALUE // "16px"
2. CSS自定义属性
@import '@serenis/design-tokens/css'; /* base + both themes + utility classes */
/* or granular: */
@import '@serenis/design-tokens/css/base'; /* root + responsive overrides */
@import '@serenis/design-tokens/css/design-tokens'; /* base + both themes (no utilities; same as CDN bundle) */
@import '@serenis/design-tokens/css/serenis-light'; /* base + light theme (standalone) */
@import '@serenis/design-tokens/css/serenis-dark'; /* base + dark theme (standalone) */
所有变量都有前缀 --srns- 范围是 :root (基地)或 .srns-serenis-light / .srns-serenis-dark (主题)。
3. Cssvar访问器帮助程序
import { cssvarSpacing } from '@serenis/design-tokens'
cssvarSpacing('md')
// → { name: 'srns-spacing-md', value: 'var(--srns-spacing-md)' }
类型: cssvarSpacing 只接受有效 SpacingName 值。
4. CSS实用类
/* app.css */
@import '@serenis/design-tokens/utilities';
这给了你映射到设计令牌的实用程序类: bg-primary-50, p-md, px-lg, mb-sm, rounded-lg, elevation-sm, font-600等。排版组合可作为 typography-paragraph, typography-public-h1等。定向间距使用短的顺风式名称(px/py/pl/pr/pt/pb 对于填充, mx/my/ml/mr/mt/mb ),映射到底层的CSS逻辑属性。不需要外部CSS框架;输出是与Safari 16+兼容的纯CSS。
响应变量
一些实用程序类具有移动优先的断点前缀,遵循以下模式 {bp}\:{utility}。支持三个断点:
| 前缀 | 媒体查询 |
|---|---|
md | min-width: 601px |
lg | min-width: 1025px |
xl | min-width: 1441px |
例如, md\:flex 适用于 display: flex 当视口宽度至少为601px时。
具有响应变体的实用程序:
- 间距填充(
p-*,px-*,py-*,pl-*,pr-*,pt-*,pb-*) - 行距(
m-*,mx-*,my-*,ml-*,mr-*,mt-*,mb-*) - 间距(
gap-*,gap-x-*,gap-y-*) - 显示器(
flex,grid,block,inline-flex,inline-block,hidden) - 伸缩方向(
flex-row,flex-col,flex-row-reverse,flex-col-reverse) - 对齐(
items-center,items-start,items-end,items-stretch,items-baseline) - 证明(
justify-center,justify-between,justify-around,justify-start,justify-end) - 软包装(
flex-wrap,flex-nowrap) - Flex简写(
flex-auto,flex-initial,flex-none,flex-1) - 伸缩(
grow,grow-0,shrink,shrink-0) - 弹性基础(
basis-1/12–basis-11/12,basis-full,basis-auto,basis-0,basis-{container})
没有响应变体的实用程序: legacy-flex 的默认样式 Flex)、间距大小(w-*, h-*, size-* 从间隔 0 仅限),容器宽度(w-{container}, min-w-{container}, max-w-{container})、自动边距(mx-auto),边界半径(rounded-*),颜色(bg-*, text-{color}, border-{color})、边框宽度(border-*),海拔(elevation-*), z-index (z-*)、字体粗细、字体系列、不透明度(opacity-*)、排版复合材料(typography-*)、位置、溢出(overflow-*, truncate),滚动行为(scroll-smooth)、线夹(line-clamp-1–line-clamp-6, line-clamp-none), sr-only,文本对齐,文本转换(uppercase, lowercase, capitalize, normal-case)、文字装饰(underline, line-through)、font-style (italic),空白(whitespace-*),断字(break-word),边框样式和过渡。
cx 助手
构建还生成一个 cx() 用于组合实用程序类的帮助器。它是通过 UtilityClassName,因此您将获得自动完成和编译时检查。它还接受条件类的对象参数——输出中包含值为true的键。根据文字键进行检查 UtilityClassName ;计算键(例如css -模块类或嵌套的 cx())通过;通过
import { cx } from '@serenis/design-tokens'
;<div className={cx('p-md', 'bg-primary-50', 'rounded-lg')} />
;<div className={cx('pt-md', { [cx('pt-0', 'bg-primary-50')]: isLarge })} />
产品毛羽: 三个ESLint规则强制执行 cx() 整个系统的使用情况。 enforce-cx-classname 需要 cx() 对所有 className 组合(没有原始字符串或模板字面量)。 cx-classnames-order 强制基于css属性的类参数的确定性排序,并删除重复项—此规则是可自动修复的。 cx-prefer-object-notation 要求条件类的对象参数(没有三元或 &&)。
如何添加令牌
-
添加到JSON:编辑适当的文件
tokens/(通常是root.json). 遵循DTCG格式:{ "my-branch": { "$type": "dimension", "$description": "Description of this token group", "my-token": { "$value": { "value": 8, "unit": "px" } } } } -
构建:跑
yarn workspace @serenis/design-tokens build。管道通过。自动发现分支$type. -
更新快照:跑
yarn workspace @serenis/design-tokens test -- -u更新黄金快照。 -
新令牌立即可用:
- JS不变:
MY_BRANCH_MY_TOKEN/MY_BRANCH_MY_TOKEN_VALUE - CSS变量:
--srns-my-branch-my-token - CSS实用程序类(例如:
my-branch-my-token)
- JS不变:
如何添加主题
-
中创建一个新的JSON文件
tokens/带有颜色/高度覆盖。 -
注册
scripts/pipeline/themeTokenRegistry.ts:{ id: 'my-theme', tokenJsonFileName: 'my-theme.json', colorScheme: 'light' } -
重建。管道产生
dist/my-theme.css和特定于主题的JS常量。
令牌类型
DTCG $type | 令牌分支 | Codegen |
|---|---|---|
dimension | 间距,容器,边界半径,边界宽度,字体大小,行高,字母间距,断点 | 注册表(简单) |
duration | 时间 | 注册表(简单) |
fontFamily | 字体类型 | 注册表(简单) |
fontWeight | 粗细 | 注册表(简单) |
number | 透明度,z - index | 注册表(简单) |
string | 媒体查询 | 注册表(简单) |
shadow | 海拔高度 | 专用(主题层) |
color | 颜色 | 专用(主题层) |
typography | 排版,typography.public | 专用(复合) |
“注册表(简单)”类型通过共享统一的代码根路径 SIMPLE_TOKEN_RESOLVERS。添加新的简单类型意味着向注册表中添加一个条目 scripts/codegen/tokenTypeResolvers.ts.
构建管道
tokens/*.json
│
├──▶ Custom codegen ──▶ dist/{types,constants,cssvar,utils}/*.{js,d.ts}
│ │
│ └──▶ esbuild CJS bundle ──▶ dist/index.cjs
│
├──▶ Style Dictionary ──▶ dist/root.css, dist/{theme}.css, dist/md.css
│ │
│ └──▶ Minify + assemble ──▶ dist/base.css, dist/serenis-light.css, dist/serenis-dark.css
│
├──▶ Style Dictionary (utility classes format) ──▶ dist/utilities.css
│ │
│ └──▶ Extract class names ──▶ dist/types/utility-class.{js,d.ts} (UtilityClassName)
│ + dist/utils/cx.{js,d.ts} (cx helper)
│
└──▶ Concat base + themes + minify ──▶ dist/design-tokens.css
Concat base + themes + utilities + minify ──▶ dist/index.css
脚本
| 命令 | 描述 |
|---|---|
build | 完整构建:codegen + Style Dictionary CSS + JS bundle |
test | 运行所有测试(包括黄金快照测试) |
test:watch | 观看模式 |
typecheck | 打印稿验证 |
lint | ESLint |
lint:fix | ESLint自动修复 |
prettify | oxfmt格式化 |
prettify:check | 检查没有写入的oxfmt格式 |
clean | 删除 .turbo, build, dist, node_modules |
许可证
PolyForm非商业1.0.0 -参见 许可证 查看全文。