
Astryx Theme-local tokens 系统规范为主题族内复用设计一条显式、可校验的路径【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx导读本文基于 Astryx 仓库docs/specs/AST-006/spec.md系统规范展开完整解析DefineThemeInput.localTokens这一可选主题本地令牌theme-local token作者接口的设计意图、11 条功能需求FR1–FR11、校验与继承模型、验证矩阵与决策记录并结合packages/core/src/theme/localTokens.ts、defineTheme.ts、generateThemeRules.ts等源码与测试用例说明它在 Astryx 中如何被实现、被验证以及作者如何安全采用。读完本文你将掌握何时应为主题族引入 localTokens、如何在defineTheme中声明与继承、哪些校验规则会被原子执行以及如何在保持既有便携式令牌词汇表不变的前提下管理主题族内的命名契约。一、规范背景为什么需要 theme-local tokensAstryx 是一个fully customizable and agent ready的开源设计系统其核心主题系统位于packages/core/src/theme围绕defineTheme与一组便携式portable语义令牌词汇表core domain tokens见 defineTheme.ts 中的TokenName类型展开。这套词汇表是全局、跨主题共享的契约被组件源码、resolveThemeToken、tokenVar等公共助手引用。问题由此产生一个被维护的主题族theme family内部常常需要把同一个语义决策例如状态填充色选中标记的墨色复用到多个组件覆盖component overrides中。如果这个决策不属于 Astryx 的便携式令牌词汇表主题作者就会陷入两难要么把私有决策硬编码进每个组件的覆盖里重复、难维护要么把它塞进全局令牌词汇表污染跨主题契约、破坏便携性。AST-006 给出的答案是DefineThemeInput.localTokens一个可选的、纯粹增量的主题族本地令牌字段。它让被维护的主题族能够复用自身的语义决策而无需把这些决策加入 Astryx 的便携式令牌词汇表主题作者获得一条显式、受校验的族内复用路径而组件作者与应用作者继续使用原有的便携式令牌契约两者互不干扰见 spec.md 的 Intent。1.1 一句话理解契约边界本地令牌声明使用任意合法的 CSS 自定义属性名作为localTokens的 key并通过同一个逐字节完全相同的名称在var(...)中引用。前缀不授予、不保留、不限制所有权——--astryx-*这类前缀没有任何特殊含义。后代主题只有通过已注册enrolled的精确extends血统才能继承注册状态仅凭拼写相似无法获得所有权。单纯从旧路径发射 CSS 不构成契约但一个已注册主题通过其同目录colocated主题规范记录并发布的定义其精确名称与语义含义在该主题族内构成公开兼容契约只是不跨主题便携、也不面向 Core 组件源码。值得注意的是规范同时声明本规范治理的是跨主题 API 与不变量独立于任何特定主题是否已完成自身的采用证据。原始 local-token 表面已发布shipped2026-09-12 的命名修订已被接受正在等待实现落地见 spec.md。二、非目标明确哪些事不做规范用一整节划清边界防止该字段被误用为通用扩展机制见 spec.md不改动现有DefineThemeInput.tokens路径的类型、接受输入、运行时/构建行为、宽松展开行为、名称、优先级、继承、输出或解析。不新增defineLocalTokens助手、第二作者操作、更短的角色标识符、引用别名或并行的本地令牌 API。不把主题本地名称加入TokenName、tokenVar、tokenVars、resolveThemeToken、生成的便携式令牌文档或 Core 组件源码。不创建面向应用消费方的令牌扩展机制——编译后的自定义属性是其所属维护主题族的实现输出不代表应用代码可以依赖它。不定义任何采用主题的角色含义、值、组件映射或证据——这些属于该主题自己的同目录记录。这一节的价值在于localTokens是主题族内的复用通道而不是应用层令牌扩展的后门也不是把私有决策偷渡进全局词汇表的捷径。三、核心需求FR1–FR11 完整解读规范主体是 11 条跨主题契约见 spec.md。下面逐条结合实现解释。FR1 — 纯增量、可选、显式注册DefineThemeInput至多新增一个作者表面可选的localTokens。提供该字段即显式注册该主题后代只有通过扩展已注册的精确 base 才继承注册。既未提供字段、也未扩展已注册精确 base 的主题保持未注册状态并且必须产生字节等价byte-equivalent的DefinedTheme数据、运行时行为、静态输出、包输出与解析行为。在 defineTheme.ts 中defineTheme调用resolveLocalTokenContract(input, base, tokens, tokenDefaults)第 576–581 行其返回结果直接决定主题对象是否携带localTokens、__localTokenOwners、__localTokenLineage三个字段。未注册的主题不会获得这些字段。FR2 — 现有令牌行为冻结本地值复用其值契约本契约不得改变tokens的类型、接受输入、运行时/静态处理、宽松未知键或广泛展开行为、名称、优先级、继承、输出或解析。已有 cast、spread、外部 CSS 变量和遗留令牌引用不得收到新的警告、失败、重新解释或迁移要求。而 opt-in 的localTokens字段内每个值必须接受完整的现有TokenValue契约CSS 字符串或[light, dark]二元组。运行时与静态构建必须复用现有tokens的值归一化语义且不改变既有路径、不归一化主题名。TokenValue类型定义于 defineTheme.ts值为string | [light: string, dark: string][light, dark]元组在主题创建时被转换为 CSS 的light-dark(light, dark)。在 localTokens.ts 的resolveTokenValue中这一归一化逻辑被原样复用于本地令牌字符串原样通过二元组转换为light-dark(...)其余形式抛出异常。FR3 — 一个精确名称贯穿每个阶段本地令牌声明必须以完整的 CSS 自定义属性名作为localTokens的 key同一个精确字符串必须贯穿var(...)引用、DefinedTheme数据、运行时 CSS、静态 CSS、继承替换、生成的主题专属类型或元数据。任何转换都不得产生第二个标识符。测试用例明确验证了这一点见 defineTheme.test.tsocean-theme与Theme.Owner等主题名配合--ac-selection-ink、--、超长生成式名称--astryx-theme-ocean-theme-color-status-fill-accent等各类合法 key均被逐字节保留生成的 CSS 包含--ac-selection-ink: light-dark(#0077b6, #48cae4);这样与声明完全一致的输出。FR4 — 接受任何合法自定义属性键每个新声明的localTokenskey 必须是合法 CSS 自定义属性名并被逐字节保留。不要求、不保留、不重写、不解释任何前缀主题名与本地令牌 key 相互独立本契约不定义任何推荐替换命名模式。isValidCSSCustomPropertyNamelocalTokens.ts使用正则^--(?:[-_a-zA-Z0-9]|\P{ASCII}|\\...)*$校验第 13–17 行支持 Unicode 与 CSS 转义。测试 defineTheme.test.ts 验证了selection-ink缺少--前缀会被拒绝并抛出/valid CSS custom-property name/。FR5 — 本地使用停留在被维护的主题族内本地名称可被定义它的已注册主题以及通过其精确extends血统注册的后代引用它不得成为跨主题便携令牌或 Core 组件源码的依赖。单纯从未注册遗留路径发射 CSS 不构成契约。而一旦已注册主题发布了在主题级规范中记录在案的本地令牌其精确名称与语义含义即成为该主题族的公开兼容契约。FR6 — 扩展是精确名称、注册与血统感知的后代只能从已注册的精确extendsbase 继承注册与声明替换继承的本地令牌只能通过重申该继承的完整名称实现。新声明无论拼写如何都归声明主题所有前缀、后缀或值相似性绝不创造所有权或血统子主题不得认领其他主题的声明。实现层面resolveLocalTokenContractlocalTokens.ts通过__localTokenOwners记录每个名称的精确所有者通过__localTokenLineage记录血统。测试 defineTheme.test.ts 展示了典型场景子主题child-theme扩展base-theme后替换继承名--astryx-theme-base-theme-color-status-fill得到__localTokenOwners[inherited] base-theme所有者仍为 base而新声明--child-surface-raised的所有者是child-theme血统为[base-theme, child-theme]。FR7 — 校验仅对已注册主题原子执行运行时与静态构建必须共享同一个递归校验器。对直接注册或通过已注册精确 base 注册的主题必须在产生任何部分输出之前校验每个声明的自定义属性语法、精确所有者与血统、与便携式tokens的冲突、以及本地令牌值/组件覆盖/媒体表面/适配adaptations之间精确声明引用的循环。适配规则中value.tokens的 key 若精确匹配有效本地声明必须失败强制作者改用value.localTokens以保留所有者、血统与循环校验。var()引用仅在精确匹配有效已注册声明时才构成本地边其余自定义属性引用一律视为外部引用前缀没有校验含义。循环检测由assertNoTokenCycles实现localTokens.ts它收集每个声明值中的var()引用构建依赖图使用 Tarjan 强连通分量算法找出环并输出形如Theme token cycle detected: --a - --b - --a.的错误。测试 defineTheme.test.ts 用VAR/vAr大小写变体构造互引含 CSS 转义名--\66 oo验证了循环拒绝。tokens与localTokens冲突测试位于同文件第 112–146 行校验在resolveLocalTokenContract第 308–319 行执行。适配中的本地令牌写入由resolveAdaptationLocalTokenslocalTokens.ts处理适配只允许替换根血统已注册的名称绝不能自行注册新名称否则抛出 cannot enroll a theme-local token 错误。FR8 — 未注册遗留行为原样保留grandfathered当localTokens缺失且精确 base 未注册时运行时与静态构建不得新增针对 CSS 自定义属性引用的扫描、拒绝、警告、保留或解释。维护者可以保持未注册或通过提供localTokens显式迁移前缀不影响任何路径。测试 defineTheme.test.ts 验证遗留主题的tokens[--astryx-theme-legacy-color-old]保持原值组件里var(--astryx-theme-missing-color-old)这类引用不被重新解释主题对象不携带localTokens、__localTokenOwners、__localTokenLineage三个字段。FR9 — 源码与构建主题保留同一条注册血统源码定义的主题与构建后的主题必须保留等价的精确本地令牌映射、注册状态与血统元数据使后代无需加载 base 样式表也能接受、继承、替换、拒绝并发射相同的名称。这解释了为什么__localTokenLineage等元数据会被保留在DefinedTheme上标注为internal见 defineTheme.tsastryx theme build生成的独立样式表需要携带完整继承信息供后续以构建主题为 base 继续扩展。CLI 侧在 build.mjs 第 1432 行附近序列化localTokens并在第 2016 行附近用localTokens in themeDef themeDef.__localTokenLineage undefined判断注册状态。FR10 — 发布后的名称与含义是兼容义务一旦已注册本地令牌发布其精确名称与记录的语义含义就是拥有主题族的公开契约。重命名本地令牌、其已注册主题或改变含义必须使用显式、经过审查的迁移或别名在兼容窗口内保留先前的精确名称、含义与血统契约。静默键替换、语义泛化、所有者重分配与推断式后代迁移均被禁止。FR11 — 同目录主题规范拥有定义与映射每个主题本地令牌定义必须存在于拥有主题的同目录主题级规范中包括精确名称、语义含义、值、映射、兼容性与渲染证据。当名称准确描述了其应用每个上下文共享的含义时使用长生成名称是可接受的。新增映射是一次主题规范兼容性审查上下文必须真正匹配文档化含义且必须为其实际明暗模式与相关交互状态提供渲染证据。四、作者视角如何使用 localTokens4.1 作者形状Authoring shapedefineTheme仍是唯一的作者操作spec.md每个localTokenskey 是var(...)、DefinedTheme、继承与发射输出中使用的完整 CSS 自定义属性名key 逐字节保留、无必需前缀值复用现有TokenValue契约字符串或[light, dark]元组归一化与tokens值完全一致采用主题的theme:*记录拥有每个具体角色、值与组件映射。在DefineThemeInput上的完整签名defineTheme.ts为/** Theme-family-local values keyed by any valid CSS custom-property name; * prefixes do not establish ownership. */ localTokens?: Recordstring, TokenValue;一个最小可用示例结合测试与文档注释const oceanTheme defineTheme({ name: ocean-theme, localTokens: { --ac-selection-ink: [#0077b6, #48cae4], // [light, dark] 元组 --brand-surface: #f6f9ff, // 双模式相同 }, components: { badge: { variant:info: {backgroundColor: var(--ac-selection-ink)}, }, }, });defineTheme解析后oceanTheme会携带{ localTokens: { --ac-selection-ink: light-dark(#0077b6, #48cae4), --brand-surface: #f6f9ff, }, __localTokenOwners: { --ac-selection-ink: ocean-theme, --brand-surface: ocean-theme, }, __localTokenLineage: [ocean-theme], }4.2 继承与精确替换基于已注册 base 扩展时defineTheme.ts 的extends字段子主题继承注册与全部声明替换继承名只需重申完整名称声明新名即获得所有权const base defineTheme({ name: base-theme, localTokens: {--status-fill: #123456}, }); const child defineTheme({ name: child-theme, extends: base, localTokens: { --status-fill: #654321, // 替换继承名所有者仍为 base-theme --child-surface-raised: #abcdef, // 新声明所有者为 child-theme }, });4.3 适配规则中的本地令牌写入适配规则可以按环境条件替换本地令牌但只能在value.localTokens中替换根血统已注册的名称themeAdaptations.ts 定义了ThemeAdaptationValue.localTokensdefineTheme({ name: app-theme, localTokens: {--touch-target-extra: 8px}, adaptations: { rules: [ { when: {pointer: coarse}, value: { localTokens: {--touch-target-extra: 12px}, // 替换而非新注册 }, }, ], }, });如果误把已注册名称写进value.tokens校验会原子失败提示改用value.localTokens。适配的本地令牌写入在 generateThemeRules.ts 的generateAdaptationRuleRules中与rule.tokens一起发射为:scope声明CSS 发射顺序在 generateThemeRules.ts 中把tokens与localTokens合并为同一个令牌块。五、平台支持与浏览器证据规范对平台支持提出明确要求见 spec.md功能/引擎下限与现有 web 主题相同的 CSS 自定义属性、light-dark()、主题作用域与浏览器支持。不支持的行为无法保留本地角色及其血统的平台编译器必须明确拒绝该已注册输入而不是静默省略或将 CSS 拼写暴露为共享跨平台 API。浏览器证据每个采用主题在真实 Chromium 中验证其实际组件映射与配色模式名称、校验、继承与运行时/静态一致性是结构性、可测试的无需视觉证据。六、当前状态影响与采用指南6.1 现状当前main分支保持了封闭的便携式 core/domain 令牌词汇表并发布了第一等的localTokens字段——目前采用基于前缀的 key 校验。2026-09-12 修订仅放宽接受的本地令牌 key 拼写实现仍待落地。到达宽松遗留路径的未知 key 仍可序列化但只有显式localTokens注册才创造所有权、引用闭合与血统校验见 spec.md。架构职责划分见 spec.md架构记录职责architecture:theme-authoring-contract可选的localTokens输入、精确名称映射、显式注册状态、扁平化继承与血统元数据architecture:theme-compilation通过共享运行时/静态编译器发射精确映射仅对直接或经精确 base 注册的主题应用递归校验器architecture:theme-tokens继续拥有不变的便携式词汇表并明确将主题本地名称排除在其公共助手与文档之外前缀无关的 key 接受仍是已命名的符合性差距named conformance gap直至其实现落地。6.2 兼容性与采用要点见 spec.md采用按主题族进行且可选字段存在不意味着现有主题被迁移。省略localTokens且不扩展已注册精确 base 的主题在DefinedTheme、运行时、静态与包输出上保持字节等价其 CSS 自定义属性引用不获得任何新扫描/拒绝/警告/保留/解释。注册接受任何合法自定义属性键迁移现有自定义属性时维护者只需在localTokens中显式声明该精确 key前缀不影响资格或所有权。现有tokens与外部变量行为保持字节等价含宽松广泛展开与运行时输入。本地名称与文档化含义发布后成为主题族公开兼容义务但永远不会成为跨主题或全局 Core 令牌承诺未注册遗留路径的单纯 CSS 发射不创造该契约。每个本地定义与映射位于所属包的同目录主题规范中每次新映射在采用前都要审查上下文是否真正匹配文档化含义并提供渲染证据。后代兼容遵循显式注册与精确血统已发布注册主题或令牌的重命名、或语义含义变更需要显式迁移或别名后才可移动后代。基础设施实现携带自己的 Changeset后续采用主题的输出变更单独携带发布说明。七、验证矩阵规范如何被证明成立规范用一张契约验证矩阵约束实现与测试见 spec.md每个契约都有代表性状态与变异/失败预期契约验证方式代表性状态变异或失败预期FR1, FR2, FR8遗留类型/运行时/构建/解析/字节输出夹具省略字段直接 tokens广泛展开cast外部自定义属性便携引用对省略字段路径新增扫描即改变遗留行为FR2本地TokenValue等价夹具CSS 字符串[light, dark]元组引用值运行时/静态归一化现有令牌对照本地值拒绝现有形式、跨路径归一化不一致或改变现有tokens对照FR3, FR4精确名称作者/类型/输出夹具不同前缀的合法自定义属性键非法键精确引用运行时与静态输出任何阶段重写 key或有效性/所有权因前缀而改变FR5, FR6, FR9源码与构建 base 注册/血统夹具根 opt-in子继承精确 base子精确替换子新角色未注册与无关名称子主题凭拼写而非精确血统获得所有权或源码/构建注册不一致FR7, FR8运行时与静态构建共享递归校验器夹具精确声明引用外部引用便携冲突适配value.tokens冲突血统不匹配循环未注册主题已注册错误发射部分输出、路径分歧、本地写入绕过value.localTokens或前缀改变引用分类FR10, FR11主题包兼容夹具、同目录主题规范与发布审查精确名称文档化含义注册主题重命名本地令牌重命名含义变更别名窗口已发布名称或含义静默变更、定义缺乏所有者或后代失去继承契约FR11逐映射主题规范审查加聚焦渲染证据精确角色含义映射组件/状态明暗模式相关交互状态映射在文档化含义之外使用令牌或未经上下文渲染证据即发布仓库中packages/core/src/theme/defineTheme.test.ts1476 行与packages/core/src/theme/tokenValueCompat.test.ts直接对应 FR1–FR9 的夹具packages/core/src/theme/themeAdaptations.test.ts覆盖 FR7 的适配场景。八、完成标准2026-09-12 修订何时符合AST-006 保持shipped命名修订在满足以下标准后达到一致见 spec.md可选的DefineThemeInput.localTokens是唯一新增的本地令牌作者表面其存在是根注册触发器无localTokens且无已注册精确 base 的主题被证明字节等价且无新的自定义属性扫描/拒绝/警告本地值接受两种现有TokenValue形式CSS 字符串与[light, dark]元组运行时/静态归一化匹配现有tokens值路径而不改变它每个合法 CSS 自定义属性 key 被接受并逐字节保留贯穿声明、var(...)使用、DefinedTheme、源码/构建继承与发射输出且无前缀语义后代仅从已注册精确 base 继承注册拼写从不创造所有权或血统自定义属性语法、令牌冲突、精确所有者与血统、循环失败对已注册主题在运行时与静态路径上原子且等价构建主题保留足以支持后代无需 base 样式表的注册与精确血统元数据每个已发布本地定义由同目录主题级规范所有其精确名称与语义含义被视作该主题族内的公开兼容契约每个新增映射通过主题规范兼容性审查并提供真实明暗模式与相关交互状态渲染证据证明上下文真正匹配文档化含义公共便携式令牌类型、助手、文档与 Core 组件源码不把本地名称暴露为跨主题 API每个采用者的同目录theme:*记录拥有其名称、含义、值、映射、迁移与渲染证据。九、决策记录六条关键决策及其否决项所有决策由cixzhang批准见 spec.md修订 — 本地令牌名称前缀无关化2026-09-12localTokens接受任何合法 CSS 自定义属性键前缀对有效性、所有权、注册与血统无任何作用。该修订取代此前 FR4、FR6–FR8、DEC-2、DEC-3、DEC-4 中记录的命名模式与保留前缀条款精确 key 保留、显式注册、所有者元数据、精确extends血统、继承、便携冲突检查与循环检查全部保持有效不定义替代命名模式。DEC-1 — 新增一个可选本地字段而不改变 tokens2026-08-31采用纯增量的可选DefineThemeInput.localTokens字段。提供它即显式注册精确后代可从已注册 base 继承注册。defineTheme是唯一作者操作tokens的所有既有行为完整保留。无localTokens且无已注册精确 base 的主题无论自定义属性拼写如何都保持字节等价。否决defineLocalTokens助手、并行 API、凭 key 拼写隐式注册、便携令牌词汇表的模块增强、或对既有令牌路径的更严格校验。DEC-2 — 保留一个精确、前缀无关的名称2026-08-312026-09-12 修订localTokens声明接受任何合法 CSS 自定义属性键声明 key 即 CSS 变量引用使用同一逐字节名称无前缀要求/保留/重写/解释主题名不决定 key。否决生成名称、引用别名、隐藏归一化以及任何基于前缀改变有效性或所有权的命名规则。DEC-3 — 将替换绑定到精确扩展血统2026-08-312026-09-12 修订后代仅从已注册精确extendsbase 继承注册替换继承的精确名称仅当该名称经由该血统到达时才被允许。新声明无论拼写如何归声明主题所有。源码与构建主题保留等价注册与血统元数据。已发布注册主题或令牌的重命名需要显式迁移或别名。否决基于前缀/后缀/值的所有权或血统推断、外部所有者认领、扩展期间的静默 key 重写。DEC-4 — 校验精确的已注册声明图2026-08-312026-09-12 修订运行时与静态构建共享一个精确校验器。直接或继承注册后检查自定义属性语法、便携令牌冲突、精确所有者与血统元数据、精确声明引用间的循环。仅当引用精确匹配有效已注册声明时才是本地边其余自定义属性引用保持外部。未注册主题不获得新扫描/拒绝/警告。前缀不参与分类。否决基于前缀的分类、宽泛的外部变量校验器或借新字段关闭遗留运行时宽松性。DEC-5 — 拥有主题规范定义公开主题族契约2026-08-31主题本地令牌定义属于拥有包的同目录主题级规范。发布后精确令牌名称与语义含义是该维护主题族内的公开兼容契约——即便该令牌不跨主题便携、也不面向 Core 组件源码。未注册遗留路径的单纯输出不足显式注册、发布与主题规范共同确立契约。长生成名称只要准确描述主题应用它的每个上下文即可接受新增任何映射都是主题规范兼容性审查上下文必须真正意味着文档化角色且必须携带其实际明暗模式与相关交互状态的渲染证据。否决把本地名称当作全局便携令牌或一次性实现细节、在拥有主题规范之外定义它们以及在仅恰好共享值的上下文中复用名称。DEC-6 — 复用完整的现有TokenValue契约2026-08-31localTokens接受完整现有TokenValue契约CSS 字符串或[light, dark]元组。在新 opt-in 字段内运行时与静态构建应用与现有tokens相同的值归一化语义复用一套既有的明暗作者模型不改变既有tokens路径、不引入另一种值形状。否决把本地值限制为纯 CSS 字符串或定义本地专属的模式语法与归一化。十、开放问题跨主题 API 层面没有开放问题。采用主题规范可保留可检查的渲染证据门槛其所有权、精确名称与语义含义不会因这些门槛被重新打开见 spec.md。结语AST-006 为 Astryx 的封闭便携令牌词汇表开了一道受控的族内复用闸门localTokens让被维护主题在不污染全局契约的前提下把自身的语义决策提升为一等作者表面并通过显式注册、精确名称、精确血统与共享递归校验器把拼写相似即归属这类隐患彻底排除。规范冻结了遗留路径、冻结了tokens行为、冻结了便携词汇表的边界把每一条新映射都约束到同目录主题规范 渲染证据的审查流程中。对于主题作者采用它是可选的对于已注册主题族它的精确名称与含义一经发布即是兼容义务——这正是设计系统主题化在可定制与可维护之间应有的平衡。延伸阅读可继续阅读 theme-authoring-contract.md、theme-tokens.md 与 theme-compilation.md 了解三个受影响架构记录的细节源码实现集中在 localTokens.ts、defineTheme.ts、themeAdaptations.ts 与 generateThemeRules.ts测试见 defineTheme.test.ts。【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考