跳转到内容

版本与兼容性政策 ​

本页回答一个问题:升级到下一个 1.x 小版本时,已依赖的公开面是否会变化。

XiHan.UI 的公开面横跨五种介质:替换自带皮肤、手写 Light DOM 结构都是 皮肤与样式分层 与 解剖与部件契约 公开说明的用法:

介质使用者写在哪里例子
JS / TS 导出自己的源码import { XhSelectRoot } from '@xihan-ui/vue'
解剖属性CSS 选择器[data-scope='select'][data-part='trigger']
data-* 状态属性CSS 选择器[data-state='open']、[data-tone='danger']
CSS 自定义属性与 @layer 名自己的样式表--xh-bg-brand、@layer xihan.overrides
自定义元素标签与 attribute自己的 HTML<xh-dialog modal="true">、data-xh-part="content"

破坏其中任何一种都不会产生编译错误、运行时异常或降级,只会表现为样式丢失或控件不响应。因此本页对五种介质逐类给出结论。

三个档位 ​

档位含义
受约束改名、删除、收窄语义 = major。新增同类成员 = minor。
只增不减只保证已有成员不消失、不改名。新增字段与条目不算破坏。
排除明确不在承诺内,任何版本都可能改。使用者不应依赖。

版本号采用语义化版本 major.minor.patch:受约束的成员变更走 major,新增走 minor,只修正行为不改名字走 patch。

18 个包必须同版本安装 ​

18 个包锁步发布:任何一个包发新版本,全部 18 个包一起发同一个号。

@xihan-ui/core     @xihan-ui/position       @xihan-ui/tokens
@xihan-ui/styles   @xihan-ui/headless       @xihan-ui/icons
@xihan-ui/vue      @xihan-ui/web-components @xihan-ui/chat-stream
@xihan-ui/markdown @xihan-ui/code-highlight @xihan-ui/backgrounds
@xihan-ui/sound    @xihan-ui/motion         @xihan-ui/animations
@xihan-ui/pointer  @xihan-ui/viz

两条后果:

  • 某个包的 major 可能不含任何针对它自身的变更。@xihan-ui/markdown 升到 2.0.0 可能只是因为 @xihan-ui/vue 修改了一个 prop。判断某次 major 是否影响当前项目,以 更新日志 的分类条目为准,不以版本号跨度为准。
  • 不混装版本。@xihan-ui/vue 与 @xihan-ui/headless 版本不一致时类型无法对齐;@xihan-ui/web-components 更严格:同一个 xh- 标签被两个版本注册会直接抛错。适配器与其兄弟包目前是普通 dependencies,包管理器不会阻止这种组合,需要使用方自行保证(见尚无门禁的条款)。

一、JS / TS 导出面 ​

18 个包中 18 个出 JS 或类型入口,共 36 个带类型的入口。

受约束 ​

类别数量说明
包名18把代码从一个包移到另一个包 = major
exports 子路径36 个 JS 入口如 @xihan-ui/vue/backgrounds、@xihan-ui/web-components/define、@xihan-ui/core/metadata。没有 ./* 通配,深路径引用(.../dist/xxx.js)会被 Node 与打包器拒绝,这些路径不是 API
Vue 组件导出 Xh*1056(136 个家族)XhButton、XhSelectRoot、XhSelectItemIndicator
Vue 组合式函数 use<家族>104useSelect、useCombobox。不使用库内部件、自行编写标记时的唯一入口
Vue 指令2vBackground(@xihan-ui/vue/backgrounds)、vSound(@xihan-ui/vue/sound),两个子入口各依赖一个可选 peer
无头内核 connect*136connectAccordion 及其参数顺序、返回的 getter 名
无头内核 *Machine80机器 schema 的形状
类型 *Props / *Api / *ChangeDetails / *Schema145 / 120 / 103 / 80删字段、改字段名、把可选改必填都是 major
Vue prop 名与未传入语义373 个不同名字 / 1335 处声明见下方说明
Vue emit 名集合67 个不同名字 / 243 处名字受约束(列在 emits 中的事件不经 $attrs 透传,删除名字会静默改变行为)
Vue 插槽名12default、item、label、trigger、panel、content、empty、indicator、mark、cell、split、tooltip

Vue prop 的未传入语义也是契约

disabled 声明为裸 Boolean(未传入恒为 false)还是 { type: Boolean, default: undefined }(未传入交由底层状态机决定),在类型上几乎没有差别,但决定了不传该 prop 时组件的表现。仓库中 202 处裸 Boolean、180 处三态、12 处 default: true、1 处显式 default: false。把某个 prop 从一种改为另一种是 major,即使名字和类型都未变。

只增不减 ​

类别数量说明
Vue 上下文类型 *Context / *Callbacks108用于给透传的 api 标注类型。只保证可读,不保证可构造:新增可选字段不算破坏,因此不要写 const c: SelectContext = { … } 这类字面量赋值
custom-elements.json(CEM)1 份 / 138 个元素已经进过清单的 tagName / attribute / event 条目不会消失;cssProperties(皮肤覆盖槽)与 events 的 type(detail 类型)由 scripts/enrich-cem.mjs 从皮肤与元素源码生成,gate:cem 校验同步。字段结构细节仍不承诺,补充算 minor

排除 ​

类别数量排除原因
@xihan-ui/headless 的内部算子与常量625clampRating、buildMonthGrid、colorHexToRgba、CAROUSEL_AUTOPLAY_INTERVAL 等。它们是内核实现的一部分,实现变化时签名随之变化。所需默认值应从组件 props 的文档默认值读取,不应 import 常量再自行比对
@xihan-ui/headless 的内部伴生类型564*Refs(机器持有的 DOM 引用袋,46 个)、ColorHsva、CascaderLevel 等,是上述函数的参数与返回类型
xxxAnatomy / xxxMeta / xxxKeyboard 三组导出对象各 136它们描述的 part 名单受约束(见第二节),但这三个对象本身的组织方式不受约束。部件名单以组件文档页的解剖表为准,不应 import 这些对象
Vue 的 provide* / use*Context 函数115Vue 适配器 已写明父子组件之间的 provide / inject 是内部实现,不对外开放。需要下探时使用 use<家族>()
Vue 的 useTimelineItem1名字形似组合式函数,实际是 inject 管道,与上一行同类
适配器运行时底座Vue 3 个、WC 8 个createVueRuntime / createVueIdGenerator / vueNormalize;createLitRuntime / createSpreader / defineElement / discoverParts / wcNormalize / MachineController 等。这些是适配器与内核之间的接缝,签名依赖的类型未从同一个包导出,无法构造调用
WC 的元素类导出 Xh*Element110仅用于 instanceof 与手动 customElements.define,不支持 extends(基类不导出、wire() 是 protected abstract)。获取元素使用 document.querySelector
WC 元素上的 static partContract136部件校验的输入数据,实现细节
dist/ 内部文件名—element-Bx4xCiT2.js 这类打包 chunk 每次构建都可能变化,不得 deep import
.d.ts 的文件布局—类型从包入口获取,不引用具体 .d.ts 路径
ui/tooling/、ui/apps/playground-*—不发布

二、解剖属性(data-scope / data-part) ​

这是更换皮肤时最核心的一组名字,也是 Web Components 使用者手写 HTML 时书写的字符串。

类别数量档位
data-scope 取值(组件身份)136受约束(新增第 137 个组件是 minor)
data-part 取值(部件名)290 个不同名字 / 1103 条「组件 × 部件」配对受约束
data-xh-part(WC 作者书写的角色声明)属性名 1 个,取值即上面 290 个受约束
meta.requiredParts(必备部件)300 条受约束(加条目 = major),方向见下

data-scope 的取值与三处完全同名,不做任何转换:headless 目录名、自定义元素标签 xh-<scope>、皮肤文件 <scope>.css。改动一处即四处同时破坏。

data-xh-part、data-xh-scroll、墨色域与液态下层的声明是 data-xh- 前缀里仅有的例外

其余 data-xh-* 属性(data-xh-scrollbar、data-xh-focus-guard、data-xh-inert-exempt 等 53 个)是库自用标记,排除在承诺之外。例外都由作者书写:data-xh-part 是 Web Components 适配器唯一的作者输入 API;data-xh-scroll 只承诺「作者容器取得 reset 层的原生细条」(见皮肤与样式分层),不进任何组件契约,删除或改名同样按公开面破坏处理;data-xh-ink 与 data-xh-ink-margin 写在作者自己的彩色区块上,声明底色极性与余量(见色彩 · 彩色面与墨色域),取值与语义按公开面承诺;data-xh-backdrop 与 data-xh-backdrop-busy 写在作者自己的图片、视频、画布区域上,声明液态面下层的明暗与杂乱(见设计令牌与主题 · 液态材质),同样按公开面承诺。作者书写 data-xh-part="trigger" 是声明,元素接线后在同一节点写入 data-scope + data-part 是事实。皮肤匹配后者,后者不应手写。

requiredParts 的方向是反的 ​

向 requiredParts 新增一条是收紧:原本可运行的 Light DOM 开始在 诊断通道 报 wc.missing-part。规则:

  • 删条目:任何版本都可以。
  • 加条目:属于破坏性变更,只出现在 major,并且落地即按 error 报告。缺少必需角色节点恒发 error,没有先以 warn 过渡一个版本的档位。

三、data-* 状态属性 ​

connect 一共产出 237 个不同的 data-* 属性名、1662 条「组件 × 属性」配对。分两类。

受约束 ​

行为契约。这些不是样式钩子,删除会使功能静默失效:

属性作用
data-value集合型组件的条目值。行为层按它反查节点执行方向键导航,Web Components 使用者需手写在 item 节点上。删除后所有集合型组件的键盘导航静默失效
data-name表单字段名(form)
data-index条目序号(0 基)

样式钩子。自带皮肤消费了 183 个属性名 / 793 条「皮肤 × 属性」配对(不含解剖的 data-scope / data-part),第三方皮肤参照的就是这一组:

属性选中它的皮肤份数
data-size79
data-state64
data-disabled58
data-variant32
data-invalid27
data-orientation / data-readonly各 26
data-placement22
data-highlighted20
data-hidden / data-motion各 18
data-dragging13
data-tone10
data-current / data-placeholder / data-empty / data-clearable …其余
data-cols-sm / -md / -lg / -xl仅 grid,断点分档名受约束

份数低不等于使用少:data-tone 的规则集中在 tone.css 一份文件中,浮层的 data-placement 同样集中在定位块中,逐份皮肤只在需要额外微调时才单独选中它们。属性名与取值的约束不按份数区分。

取值同样受约束。属性名变更会破坏皮肤,取值变更同样破坏且更隐蔽:[data-state='open'] 在取值改为 expanded 之后仍是合法 CSS,只是永远不匹配。自带皮肤当前用到的 34 个 data-state 取值全部受约束:

open  closed  checked  unchecked  indeterminate  on
active  current  incomplete  visible  hidden  ready  empty  invalid  error
completed  preparing  finishing  dismissing  picking  copying

取值的真源是 tooling/scripts/state-vocabulary.json,按族登记了 7 个族共 38 个取值:同族互斥,一个部件同一时刻只取其中一个。上面 21 个是皮肤当前选中的取值,其余只在 DOM 上出现,尚无对应的皮肤规则。check-state-vocabulary 双向校验:connect 发出词汇表外的值报错,皮肤选中词汇表中不存在的值同样报错。

三条视觉轴的取值同理。data-tone 的合法值是 6 个,唯一真源是 tone.css:

brand  neutral  success  warning  danger  info

排除 ​

其余 45 个 data-*(data-lane、data-one-way、data-checked-count、data-sticking、data-file-size、data-modules 等):自带皮肤未选中它们,组件文档页也未记载。check-state-vocabulary 每次都会列出这批发射但零引用的属性名(连同上面 data-value / data-index 两个数据载体,共 47 个)。它们在 DOM 上存在,但不承诺稳定,随时可能改名或消失。需要依赖它们编写样式时,先提交 issue。


四、CSS 自定义属性与 @layer ​

受约束 ​

类别数量说明
@layer 名与声明顺序5xihan.reset → xihan.tokens → xihan.motion → xihan.components → xihan.overrides。改名、调序、增删中间层均为 major。xihan.overrides 刻意留空,专供使用方覆盖,不会作为未使用的层被清理
全局令牌 · 原语层115--xh-color-brand-500、--xh-space-4、--xh-radius-md。皮肤中不应直接使用它们,但接入品牌轴必须写 --xh-color-brand-*,因此它们是公开的
全局令牌 · 语义层302--xh-bg-brand、--xh-fg-on-brand、--xh-control-h-md、--xh-shape-control。主题定制的正门,见 设计令牌与主题
组件覆盖槽4088(覆盖 135 个组件)--xh-button-bg、--xh-button-h、--xh-dialog-max-w。全部写成 var(--xh-x-y, 默认值) 形态,在 :root 中设置即可修改该组件
语气轴槽12--xh-_tone、--xh-_tone-on、--xh-_tone-hover、--xh-_tone-subtle、--xh-_tone-border 等。这是自定义语气的唯一机制:写入 [data-tone='premium'] { --xh-_tone: gold; --xh-_tone-on: #000 },读取这批槽的 58 份皮肤随之生效。虽然带下划线前缀,但按受约束处理
关键帧名40xh-pop-in、xh-fade-out、xh-spin。共享关键帧住在 family/motion.css(子入口 @xihan-ui/styles/motion.css),皮肤 @import 它;组件专属关键帧仍在各皮肤。在 xihan.overrides 层中重定义同名关键帧即可替换该段动画(关键帧名因此是公开面),所以改名与删名同样是 major
跨包内联属性4--xh-_truncate-lines、--xh-_float-button-offset、--xh-_tour-spotlight-radius、--xh-_carousel-autoplay-duration。由 headless 写入内联 style,皮肤必须读取。整套更换皮肤时若不读取这些值,文本截断、浮动按钮贴边、引导目标圆角或轮播进度会失效,且不报任何错误
@xihan-ui/styles 的 CSS 子路径160.、./index.css、./index.unlayered.css,家族文件 ./action-control.css、./chart.css、./collection-item.css、./field-chrome.css、./swatch.css、./material.css、./motion.css,与 148 条 .css:136 份组件皮肤加 ./layers.css、./tone.css、./reset.css、./overlay-arrow.css、./visually-hidden.css、./undefined.css、./focus.css、./label.css、./description.css、./pointer.css、./forced-colors.css
@xihan-ui/tokens 的 CSS 子路径2./tokens.css、./tokens.json

排除 ​

类别数量排除原因
其余 --xh-_ 私有槽465皮肤内部的回退中转(--xh-_bg、--xh-_bg-hover、--xh-_mention-py 等),变体只改槽位、不重写规则依赖它。不应在外部设置它们
令牌的取值—--xh-color-brand-500 这个名字受约束,其对应的 oklch() 值不受约束。调色板随视觉迭代变化,这正是令牌存在的意义
index.css 的内部结构—它是生成的扁平文件:家族配方只内联一次、排在皮肤之前,皮肤段的顺序即源序。段标记注释(/* styles/xxx.css */)只作阅读定位,不是承诺
index.unlayered.css 的内部结构—它是同一源序的扁平镜像,不带 @layer。使用该入口时没有 xihan.overrides 覆盖槽位,层名承诺不适用

命名前缀不能反推归属

--xh-field-py 形似 field 组件的覆盖槽,实际是全局语义令牌,field.css 本身并不使用它。同理 --xh-text-*(13 个全局文本令牌)与 text-field 的 48 条组件槽同前缀,--xh-color-*(43 个原语调色板令牌)与 color-picker 的 70 条组件槽同前缀。判断一条属性属于哪一档,看它在不在上表列的那 660 个全局令牌里,不按前缀推断。


五、自定义元素与 attribute ​

类别数量档位
自定义元素标签 xh-*139(defineXhElements() 注册 138 + xh-background)受约束
注册函数2(defineXhElements、defineXhBackground)受约束
observed attribute1357 条声明 / 393 个不同名字受约束(具体元素上的具体属性名)
attribute 名词汇表本身393只增不减(新组件复用 size / tone / dir 不算破坏)
CustomEvent 名96 个名字 / 210 条「元素 × 事件」受约束
事件传播语义bubbles: true, composed: true(195 处中 193 处)受约束。取消冒泡会使祖先节点上的事件委托静默失效。例外是名为 submit 的事件(xh-prompt-input / xh-question-flow):与原生表单提交同名,一律不冒泡,避免被祖先 <form> 视为自身的提交
事件 detail 形状188 个 *Details 类型受约束,等同于 headless 的同名类型
attribute: false 的 JS 字段223 条(涉及 76 个字段名)受约束。collection、translations、validate、filter 等只能通过 JS 赋值,HTML 中无法表达:不是每个 property 都有对应 attribute
命令式方法97(分布在 50 个元素)受约束,含参数与返回类型

命令式方法全清单:

元素方法
xh-formsetFieldValue setFieldError clearErrors submit reset getFieldId getFieldValue getFieldError
xh-notificationcreate updateItem dismiss dismissAll getItemsByPlacement
xh-file-uploadopenFilePicker setFiles addFiles deleteFile clear
xh-timerstart pause resume reset
xh-virtualizerscrollToIndex measureElement measure
xh-signature-padclear toSvg
xh-logscrollToBottom
xh-tourremeasure

布尔 attribute 是三态的

modal="false" 表示关闭,不写表示交由组件决定,这与原生 HTML 布尔属性(写出即为真)不同。把三态转换器换回原生语义是不改名字的语义收窄,按 major 处理。

以下与包结构有关的事实同样在承诺内:

  • 元素在 @xihan-ui/web-components/define,不在包主入口。defineXhElements() 是全量注册:调用即注册全部 138 个元素,没有逐个的 defineXhButton()。(补充细粒度 define 是 minor;补充后 defineXhElements 的全量语义即成为承诺。)
  • xh-background 单独在 @xihan-ui/web-components/backgrounds,因为它依赖可选 peer。把它移入 ./define 会强制所有使用方安装 WebGL 引擎,属于破坏性变更。
  • 元素全部是 Light DOM,没有 shadow root,::part() 不生效。CEM 中的 cssParts 条目在本包读作 data-xh-part,不是 shadow part。

六、什么算破坏性变更 ​

正例(major)与反例(minor / patch)对照,按介质各举数条。

JS 导出 ​

算破坏不算破坏
删除或改名任一 Xh* 组件(含 XhTreeSelectBranchIndicator 等低频部件)新增组件、新增部件
connectAccordion 的返回值把 getRootProps 改成 getProps给 connectAccordion 加一个新的 getter
SelectProps 新增一个必填字段,或把可选字段改为必填SelectProps 新增可选字段
SelectApi 删除一个 getterSelectContext 新增一个可选字段
把 useSelect() 的返回从 ComputedRef<Api> 换成其他容器新增 useXxx
把某个 prop 从裸 Boolean 改成 default: undefined给某个 prop 补文档
从某个组件的 emits 数组中删除一个名字向 emits 新增一个名字

解剖与 data-* ​

算破坏不算破坏
data-part 从 indicator 改成 marker给某个组件新增一个可选部件
把 item-text 改成 itemText(分词/大小写变化)皮肤内部改用其他选择器组合实现同样的视觉
某个组件不再输出 data-size / data-tone给某个组件补上原本没有的 data-tone
data-state 的取值从 open 改成 expanded新增一个 data-state 取值
把 data-disabled 从「存在即禁用」改成 data-disabled="true"—
删除 data-value删除 data-lane(在排除清单中)

CSS ​

算破坏不算破坏
--xh-button-h 改名成 --xh-button-block-size新增 --xh-button-letter-spacing
删除 --xh-radius-xl(即使库内部未使用)调整 --xh-color-brand-500 的 oklch() 值
把 var(--xh-alert-px, …) 改为直接写语义令牌(等于取消该覆盖点)给某条规则补充 @supports 兜底
调整 @layer 声明顺序在 xihan.components 里加规则
删除 ./tone.css 子路径新增 ./<新组件>.css 子路径

自定义元素 ​

算破坏不算破坏
xh-empty-state 改名成 xh-empty新增 xh-xxx 元素
某元素的 observedAttributes 减少一条给某元素新增 attribute
把 read-only 改写成 readonly把某个 attribute: false 的字段反向暴露成 attribute
事件名 value-change 改成 change新增事件名
把某个事件的 bubbles 改成 false补 HTMLElementEventMap 类型增强
xh-notification.create() 从返回 string 改成返回对象给 xh-form 新增一个方法
把某个可选 part 提升为 requiredParts新增一个可选 part

支持面 ​

算破坏不算破坏
抬高 Node 下限降低 Node 下限
抬高浏览器硬底线(使用一个无兜底的新 CSS 特性)新增一个带退化路径的增强特性
收窄 vue peer 区间(加上限、抬下限)放宽 peer 区间
撤销 ESM 导出条件增加 CJS 导出条件

七、移除流程 ​

本库不设废弃期,也不保留兼容层。改名直接改,删除直接删:不为旧写法保留别名、不把旧名放入兜底链、不在源码中标注 @deprecated 延长存续。在一个 major 中读到的名字就是当时唯一存在的名字。

移除动作集中在 major,一律出现在更新日志顶部、单列一节,逐条写明旧名与替换写法,这是唯一的迁移材料。

四种介质需要单独说明:data-*、CSS 自定义属性、@layer 名、元素 attribute 没有 IDE 提示,改名之后对应选择器只会静默失配,不报错也不降级。它们唯一的告知渠道是更新日志,因此每次移除都在 changeset 中逐条列出旧名与替换写法,使用方可据此在自己的代码库中全文搜索。


八、支持面 ​

收窄支持面按破坏性变更处理,放宽随时可以。

运行时 ​

项值变更规则
Node(安装并运行本库)≥ 18抬高 = major。产物实际用到的最高特性是 Object.hasOwn(Node 16.9),>=18 留了余量
Node(开发本仓库)≥ 24,pnpm ≥ 11与上一行无关,随时可变
模块格式ESM only无 CJS、无 node10 解析条件。包中 main / module 字段存在但指向 ESM 文件,是给旧式 bundler 的别名,不代表可以 require
包管理器无要求—

浏览器 ​

硬底线由三个无兜底的 CSS 特性决定:@layer(125/125 个样式文件使用,不识别它的解析器会丢弃整块)、oklch()(tokens.css 中 63 处,是唯一颜色来源)、color-mix()。

浏览器硬底线完整保真
Chrome / Edge111111
Firefox113121(:has())
Safari16.216.4

测试承诺:当前正式版,外加 Chromium 与 Safari 各向前两个大版本、Firefox ESR。硬底线只在 major 中抬高。

低于硬底线不会降级,而是无样式:皮肤中刻意不写兜底值,令牌缺席是缺陷而不是降级。

高于硬底线又无从兜底的特性,皮肤一律不用,由 check-css-floor 的拒绝名单拦截(@scope、@starting-style、嵌套选择器等)。其中容易误写的一条:

特性最早完整支持底线内的引擎不认时皮肤的写法
媒体查询区间写法 (width < 768px)Chrome 104 / Firefox 63 / Safari 16.4Safari 16.2 / 16.3 把整条查询判作不成立,块内规则静默丢失断点只写 (min-width: …),窄档专属规则写它的补集 not all and (min-width: …)

可选增强层(不支持时按下表退化;新增增强特性不算破坏,前提是同时提供退化路径):

特性ChromeFirefoxSafari不支持时
:has()10512115.4少量间距/gutter 微调失效
scrollbar-gutter949718.2滚动条出现时轻微位移
dvh / svh / lvh10810115.4回落到 vh
text-wrap: balance11412117.5标题按默认换行
light-dark()12312017.5代码块语法色退化成单色
field-sizing12315226.2prompt-input 输入框退化成固定行数

Web Components 侧不构成额外约束:全部 Light DOM,不使用 shadow DOM、ElementInternals、adoptedStyleSheets,平台要求只到 Custom Elements v1。

宿主框架 ​

包peer规则
@xihan-ui/vuevue: ^3.5.0下限由 useId 决定(Vue 3.5 引入)。收窄为 major,放宽为 minor
@xihan-ui/vue、@xihan-ui/web-components@xihan-ui/backgrounds(optional)不使用背景效果时无需安装
@xihan-ui/vue@xihan-ui/sound(optional)不使用音效时无需安装
@xihan-ui/web-components无框架 peer原生自定义元素,不要求任何框架
其余 15 个包无—

九、包的稳定性分级 ​

锁步发版意味着版本号不反映稳定性,因此单独列表。

下面两张表覆盖全部 18 个包,每个包必在其中一张中;门禁比对两张表的包名与 packages/ 下的公开包,新增包未定级即构建失败。

稳定 ​

破坏性变更只出现在 major,移除按上文流程执行。

包说明
@xihan-ui/vue1056 个组件、104 个组合式函数
@xihan-ui/react组件与 hooks(铺开中,公开面随批次增长)
@xihan-ui/web-components139 个自定义元素
@xihan-ui/headlessconnect* / *Machine / 各类公开类型;内部算子在排除清单里
@xihan-ui/styles136 份组件皮肤、5 个层名
@xihan-ui/tokens660 个令牌名,外加 ./runtime 的主题控制器与种子色 API
@xihan-ui/icons图标集
@xihan-ui/core只有被适配器与 headless 公开消费的那部分(createAnatomy、createNormalizer、归一化规则、状态机公开面),含 data-value 这条集合导航契约;另有 ./date 子入口的全部导出(PlainDate / PlainTime / PlainDateTime、时区换算、周规则、边界函数与格式化器)
@xihan-ui/positioncreatePositionEngine 与它的选项;其余 9 个导出是内部算子
@xihan-ui/motion缓动名、时长常量、animate、补间与弹簧算子。三值与令牌层同源(check-motion-source 比对),core / headless 与各适配器均建立在它之上,改名会先破坏库自身
@xihan-ui/pointercreatePointerSession / createMultiPointerSession 与四层几何纯函数。headless 与各适配器的拖拽、缩放、划动全部经由它,同上

实验 ​

这七个包的破坏性变更可以出现在 minor 中,不适合用于不易升级的生产代码。

包仍在变化的原因
@xihan-ui/viz图表组件按期接入,比例尺、形状、场景与过渡的签名随组件落地仍会调整
@xihan-ui/code-highlight承诺面是 HighlighterPort 端口,自研分词器(tokenizeCode、langSpecOf、LangSpec)随时可能整体替换
@xihan-ui/markdown公开面是 createStreamRenderer 与它的三个类型,外加 blockKind / fenceLang / isFenceClosed / LIVE_BLOCK_KEY 四个切块算子;解析、切块、缓存的中间件随时可能变化
@xihan-ui/chat-streamAI 会话协议类型(UIMessage、TextPart 等)跟随上游生态演进
@xihan-ui/backgrounds效果参数与点云 API 仍在调整;通用短名(bool / num / str / rgb)不是公开 API
@xihan-ui/animations公开面是 MotionSpec 的字段与 BUILTIN_MOTION_NAMES 里的预设名。预设表随组件接入继续调整,预设改名没有门禁拦截:它不是导出名,删除不会被报告
@xihan-ui/sound同上:SoundSpec 的层与包络字段、三套主题、BUILTIN_SOUND_NAMES 中的预设名仍在调整

门禁覆盖范围 ​

已由门禁保证 ​

六种介质的改名即 major 已有门禁保证。pnpm gate:surface 运行的 check-public-surface 以入库基线(ui/tooling/public-surface.json,16366 个名字)比对当前状态: 基线中有而当前没有,即为删除或改名,构建失败。新增一律放行,因为新增是 minor。

覆盖:包名与 198 条子入口、8513 个导出名、136 个 data-scope 与 1103 条部件配对、 136 个组件的 1763 个 prop 名、239 种 data-*、34 个 data-state 取值、660 个令牌、 5 个 @layer 名、4088 个组件覆盖槽、138 个自定义元素及其 attribute 与事件。

prop 名一维是后补的:在它加入之前,修改一个 prop 名(实测 transfer 的 items 改 collection、splitter 的 size 改 sizes)其余门禁全程沉默。它的事实源是无头内核的 <组件>Schema['props'],各适配器的 props 均按它展开。

它的必要性可以复现:把 switch 的 thumb 改名 knob,其余门禁全部通过, 只有这一道拦截;把 switch 的 checked 改名 isChecked,同样只有它报出 「组件 prop switch: checked」。删除一个语义令牌、修改一个组件覆盖槽名同理。

确需破坏性变更时,运行 pnpm surface:update 更新基线并在 changeset 中说明: 门禁拦截的是无意删除,不是有意的 major。

基线锁定的名字比本页承诺的范围宽

基线是所有可写出名字的机械快照,不区分档位:本页归入排除的成员同样在内,包括 headless 的 625 个内部算子与常量、564 个伴生类型、*Anatomy / *Meta / *Keyboard 三组导出对象, 以及六个实验包的全部导出。政策允许随时删改它们,但删除仍会触发门禁。 行使这份删除权时先运行 pnpm surface:update 更新基线,这不是破坏性变更, changeset 按 patch / minor 记录即可:更新基线这一动作本身不代表 major。

另有三道门禁把原本依赖自觉的条款转为机器检查。check-css-floor 保证浏览器硬底线: .browserslistrc 记录底线,拒绝名单拦截 @scope、媒体查询区间写法等无兜底的抬底线特性, light-dark() / dvh / lh 必须带级联兜底。check-version-lock 保证 18 包锁步:任何一个 package.json 的 version 与其余不同,门禁直接失败。check-wiring 保证检查系统自身:新增的 check 脚本未接入 pnpm gate 等同于未编写,死引用同样被拦截。

三条视觉轴已收敛为联合类型,tone / size / variant 不再是裸 string, 写错取值在编译期报错。Vue 事件载荷已有类型,101 个组件的 emits 全是对象式, 产物 .d.ts 中不再出现 (...args: any[]) => any。

尚无门禁的条款 ​

以下条款目前没有门禁。

条款现状计划补充的机制
Vue 作用域插槽载荷带载荷的插槽已声明 slots: 选项,由 check-slot-types 门禁的四条判据保证(缺声明 / 键非可选 / 值非函数 / 声明未用)。仅渲染无载荷插槽的部件仍不声明,消费方写错 slot 名不会报错无载荷插槽也补充声明,或明确只有带载荷的插槽进入契约
移除提示(CSS / data-* / attribute / 层名)这四种介质没有 IDE 提示:名字移除之后,消费方的声明只是静默失配,既不报错也不降级。唯一的告知渠道是更新日志,因此每次移除都在 changeset 中逐条列出旧名与替换写法,供使用方在自己的代码库中全文搜索无
浏览器硬底线已落地:.browserslistrc 记录硬底线,check-css-floor 门禁拒绝抬底线的无兜底特性(@scope、媒体查询区间写法等),并校验 light-dark() / dvh / lh 的级联兜底拒绝名单改动时联动本页支持面表格的提醒
「18 个包必须同版本」check-version-lock 门禁保证 18 个 package.json 同版本。运行期一侧只在 dev 有提示:三个适配器启动时调用 checkLockstepVersion,自身版本与 core 不一致时经诊断通道发出一条 warn;生产构建中跳过,且只比对适配器与 core 两个版本,不是全部 18 个提升为 peer,或把运行期比对扩展到全部包

本页内容与实际行为不符时按缺陷处理,请提交 issue。

Released under The MIT License