@xihan-ui/web-components 1.0.0-alpha.2 → 1.0.0-alpha.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,536 @@
1
1
  # @xihan-ui/web-components
2
2
 
3
+ ## 1.0.0-alpha.3
4
+
5
+ ### Major Changes
6
+
7
+ - d0202b2: **选择态一族(table / tree / transfer)的选中集合统一叫 `selection`。** 三个组件表达的是同一件事,
8
+ 却各叫各的:table 是 `selection`、tree 是 `selectedValue`、transfer 是 `selected`。1.0 之后 prop 名
9
+ 就是公开 API,趁 alpha 一次改完,不留别名。
10
+
11
+ 三家统一为 `selection` / `defaultSelection`,回调仍是 `onSelectionChange`,载荷字段一律 `{ value }`
12
+ (全库同类载荷都用 `value`,transfer 的 `{ selected }` 是唯一破例)。
13
+
14
+ 迁移点:
15
+
16
+ - tree:prop `selectedValue` → `selection`、`defaultSelectedValue` → `defaultSelection`;
17
+ `TreeApi.selectedValue` → `selection`、`setSelectedValue` → `setSelection`;
18
+ 机器事件 `SELECTED.SET` → `SELECTION.SET`;Vue 的 `v-model:selectedValue` → `v-model:selection`;
19
+ WC 的 `el.selectedValue` → `el.selection`、`el.defaultSelectedValue` → `el.defaultSelection`。
20
+ - transfer:prop `selected` → `selection`、`defaultSelected` → `defaultSelection`;
21
+ 载荷 `TransferSelectionChangeDetails.selected` → `value`;
22
+ `TransferApi.selected` → `selection`、`setSelected` → `setSelection`;
23
+ 机器事件 `SELECTED.SET { selected }` → `SELECTION.SET { value }`;
24
+ 纯函数入参与 `TransferMoveInput` / `TransferMoveResult` 的 `selected` 字段 → `selection`;
25
+ Vue 的 `v-model:selected` → `v-model:selection`,默认插槽载荷 `selected` → `selection`、
26
+ `setSelected` → `setSelection`;WC 的 `el.selected` → `el.selection`、
27
+ `el.defaultSelected` → `el.defaultSelection`。
28
+ - table 本来就是这套名字,不变。
29
+
30
+ 三者的语义各不相同,改的只是名字:table 的 `selection` 可以是 `'all'`,tree 分单选/复选,
31
+ transfer 的 `selection` 是两侧的勾选集合,与「已搬到右侧」的 `value` 是两回事。
32
+
33
+ ### Minor Changes
34
+
35
+ - 906b712: 真机 axe 扫出的无障碍缺陷逐条修,并把三个模态补进扫描名单。
36
+
37
+ **dialog / drawer / image-viewer 此前从没被真机 axe 扫过**:它们的 presence 模型与共享套件对不上,各自单开了一份 WC 规格,因而不在扫描名单里——而焦点陷阱、`aria-modal`、背景 inert 恰恰最该在真浏览器里验。补进名单后三者全绿。
38
+
39
+ 同一次扫描照出四类既有缺陷:
40
+
41
+ - **side-nav 折叠成图标栏后,行按钮与链接没有可及名**(critical + serious,14 条):皮肤把 `branch-text` / `link-text` 整个 `display: none`,可及名随之归零——读屏用户在折叠侧栏里完全不知道每一项是什么。改成仓内既有的视觉隐藏配方(文字仍在无障碍树里),可及名恒等于可见文本,不必再让连接层去猜名字,也不会覆盖作者自己写的 `aria-label`。
42
+ - **side-nav 的 `ul` 直接装 `a`**(serious,19 条):Vue 适配器早就偷偷包了一层没登记的 `<li>`。把它提成正式的 `item` 部件(解剖 / connect / meta / 两个适配器 / 套件 / 示例同步),与同族的 breadcrumb、anchor、navigation-menu 一致。
43
+ - **有值时下拉钮被藏掉**(date-picker / time-picker / combobox):清空钮的互斥契约此前让「清空钮顶替下拉钮」,但这三家的 `trigger` 是打开浮层的那颗按钮而不是装饰箭头——藏掉它,鼠标用户在有值之后没有入口,浮层收起时的焦点归还也会落到隐藏节点上,键盘用户当场丢失位置(真机里 Escape 后焦点掉到 `body`)。改为只有纯装饰的 `indicator` 才让位(select / cascader / tree-select 那三家),这三家的清空钮与下拉钮并排显示。
44
+ - select 的隐藏原生 `select` 在派生用例里被插了两份,第二份没有接线因而没有可及名——套件的 fixture 助手补幂等判断。
45
+
46
+ `data-name` 这类写成常量再当计算键用的属性,此前公开面采集器的正则扫不到,基线漏登记;采集器补上常量形态。新增 `check-release-tag`:标签写的版本号必须与 changesets 的 pre 模式对得上,否则打 `v1.0.0` 却发出 `1.0.0-alpha.N`、或退出 pre 后打 `v1.0.0-rc.1` 直接占掉 `latest`。
47
+
48
+ - e12e337: 日历可以并排展示连续几个月,date-picker 的区间选择默认就是两个。
49
+
50
+ 区间的起止常常跨月,只有一个面板就得「点起点 → 翻页 → 点终点」,翻的时候还看不见起点在哪。
51
+ 两个并排是这类选择器的通行做法,也是这次补上的。
52
+
53
+ - **calendar 新增 `visibleCount`**(默认 1)与 **`panels`**:一个锚点铺出 N 个连续月,
54
+ 翻页只动锚点、整窗一起走一个月,不是各翻各的。跨年自然接上(12 月的下一个面板是次年 1 月)。
55
+ - **`getGridProps` / `getHeadingProps` 收面板下标**,每个面板一份标题 id,网格各由自己那行标题命名。
56
+ 不给下标即首个面板,旧调用一字不改。
57
+ - **`CalendarCellProps` 多一个 `index`**:同一天会同时出现在两个面板里(8 月末那几天也铺在 9 月首行),
58
+ 「是不是本月」只有连着面板一起看才判得出来。
59
+ - **往后翻的边界按整窗算**:新露出来的是窗口末尾再往后一个月。单面板时与从前逐字一致。
60
+ - **date-picker 新增 `visibleCount`**,缺省单选 1、区间 2。
61
+ - 皮肤只在 `content` 直接摆了两张日历时才横排(`:has`),并给第二张起画一道左分隔线——
62
+ `showTime` 那套结构里 content 的直属子节点是作者自己的包裹块与确认行,无条件横排会把它们并到日历旁边去。
63
+
64
+ 旧字段 `weeks` / `visibleMonth` / `headingLabel` 保留,恒指首个面板。
65
+
66
+ - ff84a16: 日历补上按月 / 季度 / 年 / 周挑,并修掉多面板下的两处硬伤。
67
+
68
+ **面板粒度 `view`**(`day` 默认 / `month` / `quarter` / `year`)
69
+
70
+ 格子的值一律是「那段时间的第一天」的 ISO 串,不另立一套值形态——min/max 比较、区间逻辑、
71
+ 不可用判定、表单出口于是全都原样复用。点 Q3 落的就是 `2026-07-01`。
72
+
73
+ - 月面板一年 12 格、季度 4 格、年面板一页十年(两端各带一格邻十年,与日视图带邻月同一套做法)
74
+ - 一页翻多久跟着视图走:日 1 个月、月与季度 12 个月、年 120 个月;翻页边界同样按整页算
75
+ - 标题按 locale 出:`2026年8月` / `2026年` / `2020年-2029年`
76
+ - 网格上多一个 `data-view`,皮肤据此换排布(月与年 3 列、季度 4 列);日视图一个字没动
77
+
78
+ **周选 `weekSelection`**:点任意一天落的是它所在的整整一周(两端一起给),周首日随 locale。
79
+ 只在 `view=day` 且区间模式下生效,其余情形照旧只落这一天。
80
+
81
+ **修:点第二个面板里的日子会整窗往后翻一页**
82
+
83
+ 视窗起点此前直接由聚焦日反推,于是点右边那个面板 → 聚焦日落到下个月 → 整窗跟着走,
84
+ 看着就像「点一下翻一页、根本选不中」。现在视窗是独立的浏览位置,只在聚焦日走出视窗时
85
+ 才挪过去,挪到刚好把它露出来的那一端。
86
+
87
+ **修:浮层展开后指针那条路没有出口**
88
+
89
+ 上一版把触发钮变成可选部件后,点输入行只能展开、不能收起——而段位里敲出来的值又不触发
90
+ 「选完即收」(那时人还在打字),于是浮层关不掉。现在点输入行是开合对称的,段上按 `Enter`
91
+ 也收起(`Alt+ArrowDown` 展开的对偶)。
92
+
93
+ - a55c76e: 日历补上快速翻年、周选整周预览,日期示例按粒度重整。
94
+
95
+ **« / » 快速翻**:新增 `prev-year-trigger` / `next-year-trigger` 两个可选部件(不写即不渲染),
96
+ 步长跟着视图走——日视图一年,月与季度十年,年视图一百年(它的 `‹ ›` 本来就走十年,
97
+ 大步得更大才有用)。边界与 `‹ ›` 各判各的:上界卡在今年之内时,下一页还翻得动、整年跳出去就按不动了。
98
+
99
+ **周选悬停整周亮**:`weekSelection` 下指针扫过哪一行哪一行整整七天一起亮,与点下去的结果对得上。
100
+ 此前沿用的是「起点 → 悬停点」那一段,一格一格拉出来的区间在周选里讲不通。不开周选时照旧。
101
+
102
+ **示例重整**
103
+
104
+ - 天 / 周 / 月 / 季度 / 年归拢成一个「五种粒度」示例,一套结构走完
105
+ - 「区间选择」补齐五种粒度,都是并排两页
106
+ - 删掉旧的「按月选择」——它是 `view` 出现之前手搓的一版面板(拿 `XhButton` 拼的),
107
+ 与新的 `view="month"` 长相不一致;它想演的「输入行只留年月两段」并进新示例,
108
+ 按年挑就只留年那一段
109
+
110
+ - 089db90: 清空 / 关闭 / 移除按钮收成四类契约(`开发设计/UI.ClearTrigger.Contract.md`),`check-clear-trigger` 门禁固化。
111
+
112
+ **内嵌清空钮**(cascader · tree-select · combobox · date-picker · time-picker · text-field · tags-input · select,以及新增部件的 popselect · date-field · time-field)统一为:`tabindex=-1` 不占 Tab 位但**不再 aria-hidden**——读屏按 `aria-label` 找得到它,文案统一走 `translations.clearTrigger`(缺省 `'Clear'`;select 的 `clear` 键改名);pointerdown 不夺焦,点完发 `VALUE.CLEAR` 并把焦点送回宿主(trigger / input / 第一段);没值就 `hidden`,不再同时打 `disabled`/`data-disabled`、皮肤也不再留一颗永远看不见的灰钮;尺寸与圆角统一为 `var(--xh-<c>-action-size, var(--xh-control-action-size))` / `var(--xh-<c>-action-radius, var(--xh-shape-control))`——text-field 此前与输入框等高、select / tags-input 按指示符尺寸走 pill,`--xh-text-field-clear-*` / `--xh-tags-input-clear-*` / `--xh-select-clear-*` 槽改名 `action-*`;互斥一律由 connect 在被让位的部件上打 `data-clearable`、皮肤一条 `display: none`——select 去掉了 `:has()` 让位与 `:hover` 才显形(触屏此前根本看不到清空钮),清空钮改为 trigger 的兄弟并排(`--xh-select-control-gap`)。
113
+
114
+ **键盘清空**:select · cascader · tree-select · popselect 此前没有任何键盘清空路径。现在焦点在 trigger、有值且可编辑时 **Delete 清空全部、Backspace 单选清空 / 多选去掉最后一个**,键盘表与一致性套件同步。
115
+
116
+ **select** 补 `readOnly`(浮层照常展开、值改不动、清不掉)与 `VALUE.CLEAR` 事件(`api.clear()` 不再借 `VALUE.SET []`);Vue 的 select / combobox Root 新增 `clearable`(缺省 false)决定 collection 自动渲染树是否带清空钮——combobox 此前无条件渲染,示例已补 `clearable`。
117
+
118
+ **独立动作钮**(file-upload · signature-pad):file-upload 的 `api.clearFiles()` 改名 `clear()`、`translations.clearFiles` 改名 `clearTrigger`;列表为空时不再原生 disabled(清完焦点会掉回 body),只打 `data-empty` 压淡。
119
+
120
+ **浮层关闭钮**(dialog · drawer · popover · tour · toast · alert · floating-panel · image-viewer)统一 `var(--xh-<c>-close-size, var(--xh-control-h-sm))` / `var(--xh-<c>-close-radius, var(--xh-shape-control))`,dialog / drawer / popover / tour 补上使用者槽;image-viewer 保持 `--xh-control-h-lg`(全屏看片的 chrome 钮按触控靶走)但圆角归 control。**标签内移除钮**(tag · tags-input item · select tag)尺寸基准 `--xh-control-indicator-size`、圆角 `--xh-shape-inset`;行级删除钮(file-upload item · dynamic-input)按 `--xh-control-action-size` / `--xh-shape-control`。
121
+
122
+ 四类按钮都补了 `:active` 按压反馈(`--xh-motion-scale-press`),27 处登记进 `check-press-feedback`。
123
+
124
+ `--xh-select-clear-*` / `--xh-tags-input-clear-*` / `--xh-text-field-clear-*` 共 20 个槽名变更是公开面删减,基线已推。
125
+
126
+ - ada8a01: 全局配置做成真正的 ConfigProvider:全局默认 + 局部覆盖,两个适配器一份语义。
127
+
128
+ **嵌套注入改成逐键合并。** 此前子树里再 `provideXhConfig` 会把外层整份遮蔽——只想改一句文案,外层的 `locale` 与 `portalContainer` 一并丢掉,而文档一直把「不同子树各注各的」当卖点。现在键缺席与写成 `undefined` 都算「这一层没说」,一律回落外层;同一个组件下的文案也按键并。
129
+
130
+ **Web Components 侧补上作用域。** 新增 `<xh-config>`:包住一棵子树,里面的元素沿 DOM 祖先链解析配置,合并规则与 Vue 侧完全一样(那边找组件树,这边找 DOM 树)。`setXhConfig` 仍管整页。元素自己不渲染任何东西,`display: contents`。
131
+
132
+ **新增两个字段。** `size` 是尺寸档的应用级默认(对齐 AntD 的 `componentSize`),落到每个声明了三轴 `size` 的组件上;`floating-panel` 的 `size` 是一对像素数、同名不同义,两侧都在豁免名单里。`scrollRoot` 交出真正在滚的那个元素——宿主把滚动搬进内容容器时 `body` 本身不滚,模态浮层的滚动锁此前是空操作。`dir` 刻意不收:它走 DOM,行为层从计算样式读,再加一条 JS 通道只会对不上。
133
+
134
+ **补上三处漏接。** `context-menu` 与 `tree-select` 声明了 `translations` 却没走 `withXhConfig`,全局文案对它们一直静默失效;`XhTranslationOverrides['date-field']` 指的是 `DatePickerTranslations`(`startDate` / `endDate`),而 `date-field` 的文案是逐段映射,类型过得去、运行期 100% 不命中,现改为 `DateFieldTranslations` 并把它从空接口填成段位映射。
135
+
136
+ 新增 `check-config-wiring` 门禁:两侧配置面字段必须一致、`size` 豁免名单两侧一致且与 headless 的类型对得上、声明了 `translations` 或三轴 `size` 的 Vue 组件必须真接上配置通道。
137
+
138
+ - e2292bf: date-picker 与 time-picker 补上三条视觉轴:`variant` / `tone` / `size`。
139
+
140
+ 这两个组件此前是全仓仅有的两处「有输入行却没有形态轴」——同一张表单里,
141
+ 文本框、数字框、分段日期、分段时间都能换档,唯独这两个换不了,只能靠覆盖令牌硬凑。
142
+ 它们各自内嵌的 `date-field` / 分段时间输入早就有三轴,缺的一直是外层这一份。
143
+
144
+ 轴的落法与全仓一致:三个属性只写在 `root` 上,输入行、日历格与浮层里的列都从那里继承皮肤声明的私有槽,
145
+ 所以换一档不必给每个部件各写一条选择器。
146
+
147
+ 皮肤同步把两份里原先散着的写死值收成私有槽:
148
+
149
+ - 尺寸档换 `control-h` / `control-px` / 两档字号(time-picker 还多一个列表格子的内边距)
150
+ - 形态档换底色与两档描边;输入类照例不做实心档——填满一个要往里打字的框,字与底没法同时读
151
+ - 语气只落在聚焦环、段位反白、时间列选中与确认按钮上,正文与日期数字不归它管
152
+
153
+ 不写这三个属性时一个 `data-*` 都不产出,皮肤走缺省档,观感与之前逐像素一致。
154
+
155
+ - d0202b2: 开箱默认语言跟随运行时,兜底英文。
156
+
157
+ 此前是自相矛盾的:i18n 文档明写「内建文案默认是英文」,而日期系的兜底 locale 写死 `zh-CN`(calendar / heatmap / time 三处常量)——开箱就是**英文按钮配中文月份名**,热力图图例还是「少 / 多」。命令式 dialog 的按钮也硬编码着「确定 / 取消」,而那个服务自建 `createApp` 挂在 body 上,根本读不到组件树里的 `provideXhConfig`。
158
+
159
+ 现在 kernel 提供一条解析链 `resolveLocale(locale, scope)`:**作者显式传的 locale → 全局配置 → 宿主 `navigator.language` → `en-US`**。宿主读取一律经 `config.scope`(SSR 安全)。calendar / heatmap / date-field / date-picker / time 全部接上;`RuntimeConfig.locale` 的 `zh-CN` 兜底同改。
160
+
161
+ **行为变更(预期之内)**:默认周首日随之从周一变成周日(`en-US` 口径)——要固定就显式传 `locale` 或 `firstDayOfWeek`。同时修掉一个此前没有测试覆盖的连带 bug:日历的周序号原先取每行**行首**那天算 ISO 周数,注释写着「行首正是周一」;周首日变成周日后,周日在 ISO 里属于上一周,整列周序号会集体少 1——改成取行内第 4 天,两种周首日下都必落在本行覆盖的那个 ISO 周内。
162
+
163
+ `TimeProps.locale` 此前是 `'zh-CN' | 'en'` 的窄联合,与全局配置的 BCP 47 `locale` 对不上:配 `de-DE` 会让所有非 `'en'` 的语言(含 `en-US`)拿到中文用词。类型放开为 `string`,判据改成 `zh` 前缀匹配,`TimeLocale` 直接删除、不留别名。`HEATMAP_LEGEND_TEXT` 的「少 / 多」改 `Less / More`。
164
+
165
+ `createDialogService` / `createToastService` 新增 `config?: XhConfig` 选项——服务在自己那棵子树里 `provideXhConfig` 一次,不造全局单例;按钮兜底改 `OK` / `Cancel`。
166
+
167
+ 登记未接的两处(都写进了 i18n 文档):`time-picker` / `time-field` 的 `locale` 只影响小时制推断,接上宿主会让 `en-US` 环境静默翻成 12 时制,属另一条裁决;`heatmap` 的 `firstDayOfWeek` 是独立的 prop 轴,不随 locale 走。
168
+
169
+ - 0be028c: 抽屉可以挂在页面里的某一块区域上了,`portalContainer` 也不再是个死字段。
170
+
171
+ `RuntimeConfig.portalContainer` 自打声明起就没人读过——全部浮层的搬运目标一律写死 `'body'`,
172
+ 所以「局部抽屉」根本做不出来。这次两头一起接:
173
+
174
+ - **drawer 新增 `contained`**:遮罩与定位层从 `fixed` 换成 `absolute`,只罩住最近的定位祖先而不是盖满整屏。
175
+ `data-contained` 同时落在 root / backdrop / positioner / content 上,页面里那半边与被搬走的那半边都能选到。
176
+ - **Vue 新增 `container`**(选择器或元素):浮层搬进那个容器,并**隐含 `contained`**——
177
+ 一处给定、两件事从它派生,不会出现「搬进去了但还画着全屏遮罩」这种两边各说各话。
178
+ 显式写了 `contained` 以显式的为准。
179
+ - **`portalContainer` 真正接上**:`XhConfig` 多一个同名字段,应用级注入一次,
180
+ 没写 `container` 的浮层就落到它给的容器里;都没有才落 `body`。
181
+ - **Web Components** 是 Light DOM,作者写在哪浮层就在哪,因此只需要 `contained` 这一个属性来让皮肤按容器画。
182
+
183
+ 那个容器要自己带 `position`(`relative` 之类),否则 `absolute` 会往上找到别的定位祖先——
184
+ 这一条写进了 props 说明与示例。
185
+
186
+ - 1e90ce6: 热力图新增 `palette` 色板轴:`green` / `blue` / `orange` / `purple` / `red` / `gray`,直接按颜色点名色阶满档那一端,三种形态与图例一起跟着走。它是装饰性的一条轴,不是第四条语义轴——与 `tone` 同时写时听色板的,两条都压不过作者自己写的 `--xh-heatmap-ink`;不写时行为与之前逐字一致。
187
+
188
+ 令牌层随之补上紫色原语 `--xh-color-purple-600`:明度与彩度照 danger 的 600 档,只把色相换成 302。
189
+
190
+ - 8d35702: 动效与浮层口径收口(`开发设计/UI.MotionOverlay.Contract.md`)。
191
+
192
+ **减弱动效只剩一条通道。** 此前 kernel 的 `RuntimeConfig.reducedMotion` 只读系统 matchMedia、motion 包的 `setMotionOverride` 只有 animate / 滚动 / 数字动画在听,presence 与 stick-to-bottom 感知不到应用级覆盖;无 matchMedia 的宿主两包还给出相反答案(kernel 直接抛 TypeError、motion 报 reduce)。现在 kernel 依赖 motion,`reducedMotion` 缺省即 `resolveMotionPreference() === 'reduce'`(覆盖 ?? 系统偏好),没有 matchMedia 一律不减弱;glyph 转圈、backgrounds、滚动、数字动画全部走同一函数。CSS 侧 `tokens.css` 新增 `:where([data-motion='reduce'])` 块,与 `@media (prefers-reduced-motion: reduce)` 同源生成、逐条相同——作者把 `data-motion="reduce"` 打在任意容器即局部减弱。全局配置加 `motion?: 'reduce' | 'no-preference'`,Vue `provideXhConfig` / WC `<xh-config motion>` 收到即调 `setMotionOverride`。
193
+
194
+ **缓动与时长的真源是令牌。** motion 包新增 `durations = { fast, normal, slow }`,`animate()` 缺省与 `@xihan-ui/animations` 的缺省时长都引它;`check-motion-source` 比对 primitive.json 与 easing.ts / durations.ts,值不等即红;`check-reduced-motion-channel` 禁止 motion 包之外再出现 `matchMedia('(prefers-reduced-motion')`。
195
+
196
+ **皮肤的 reduce 块归口。** 只在两种情况自写:无限循环动画要整个停掉、有使用者时长槽的过渡要兜住穿透。image-viewer / side-nav / layout 三份纯重复令牌层的块删掉;table 的 `0.01ms !important` 改 `animation: none`;保留的 10 份每块配一份等价的 `[data-motion='reduce']` 规则。animation / transition 不再直引 `--xh-duration-*` 原语:spinner 走 `--xh-spin-duration`,skeleton 走新令牌 `--xh-shimmer-duration`(1600ms)。`check-infinite-motion` / `check-motion-primitives` 守住。
197
+
198
+ **浮层的 placement / offset 默认值只有两种语义。** `OVERLAY_PLACEMENT_ANCHORED = 'bottom'`(气泡类)与 `OVERLAY_PLACEMENT_LIST = 'bottom-start'`(列表类)、`OVERLAY_OFFSET = 8` 从 headless 共享导出,各组件的 `<C>_DEFAULT_PLACEMENT` 改为引用它们(tooltip / hover-card / popover / popconfirm / popselect 新增导出常量),所有机器显式传 offset,不再隐式靠引擎兜底;`check-overlay-defaults` 守住。
199
+
200
+ **层级覆盖槽齐全、后缀统一。** 22 个浮层族的 positioner / backdrop、toaster、navigation-menu 面板都有了 `--xh-<c>-layer` 槽(缺省仍是 `--xh-layer-*`);tour / table / heatmap 的 `-z` 后缀槽改名 `-layer`(7 个,公开面变更,基线已推)。
201
+
202
+ **进退场对称。** toast 退场位移从 distance-sm 改 distance-md(与进场、与 dialog 一致);tour 的气泡改用 pop 族,聚光灯补退场;side-nav 折叠态弹出面板补进退场并在 Vue / WC 接上退场租约。
203
+
204
+ **navigation-menu 的定位登记变成可验证的。** 三道浮层门禁此前按「anatomy 有 positioner」发现族,它从没被检查过;现在 `SKIN_POSITIONED` 名单要求它没有 positioner、不接引擎、面板由皮肤 absolute 排布,任一条不成立即红。`check-arrow-geometry` 增比对 JS 箭头常量(8·√2 / 8)与令牌(8px 边长 / 8px 圆角)。
205
+
206
+ - d738f78: `date-picker` 与 `time-picker` 新增快捷选项:给 `presets` 数据就在浮层里多排一列(「今天」「近 7 天」「此刻」这类),点一条整份写进值。新增 `presets` / `preset` 两个部件、`getPresetsProps` / `getPresetProps` 两个产出与两条键盘行;这一列自成一套 listbox 键盘,与日历网格、时分秒那几列互不抢键。
207
+
208
+ 单日的值就是一条 ISO 日期串,区间用 ISO 8601 的区间写法把两端拼起来(`2026-08-15/2026-08-21`),一个串同时充当这一项的身份。日子由使用者算好传进来——连接层每帧求值,`today()` 放进渲染期会跨零点算出两个答案;headless 备了 `datePickerPresetDay` / `-Range` / `-Month` / `-Year` 与 `timePickerPresetNow` 五个纯函数。
209
+
210
+ date-picker 的收起沿用 `closeOnSelect` 那条守卫(区间要两端齐、showTime 仍由确认按钮收口);time-picker 的快捷选项给的是整份时间,写完即收。
211
+
212
+ - 516bd46: 浮层搬进单一落点,层号与背景失活跟着改口。
213
+
214
+ ## 浮层不再原地渲染
215
+
216
+ 此前 20 个带 positioner 的浮层里只有 dialog / drawer / image-viewer 搬走,其余 16 个
217
+ 留在触发器旁边。坐标一直是对的(定位引擎特意处理了「祖先抢走包含块」),坏的是层叠序:
218
+ 宿主应用的祖先只要建了层叠上下文——`transform` / `translate` / `scale` / `filter` /
219
+ `backdrop-filter` / `opacity` 小于 1 / `contain` / `will-change` / `position: sticky` /
220
+ 定位元素带 `z-index` / `isolation`——浮层的层号就退化成那个上下文里的局部序号,被任何
221
+ 上层兄弟盖住。这是库无法从自身约束的:宿主怎么写 DOM 不归库管。
222
+
223
+ kernel 新增 `ensurePortalRoot(doc)`,在 body 末尾维护单一 `#xh-portal-root`,
224
+ `RuntimeConfig.portalContainer` 的默认值指向它。Vue 侧 19 个浮层的 positioner
225
+ (tour 连同 backdrop 与 spotlight)一律 Teleport 过去。落点自身一条样式都不写——
226
+ 子元素全是 `position: fixed`,不占布局,而任何 `position` / `transform` / `contain` /
227
+ `isolation` 都会平白建出新的层叠上下文,正是要躲的东西。
228
+
229
+ WC 适配器是 Light DOM,解剖契约就是「作者写在哪就在哪」,搬不动。改为在浮层展开时
230
+ 沿祖先链探一次层叠上下文,命中就投一条诊断,指名是哪个祖先的哪条属性。
231
+
232
+ **破坏性**:浮层的 DOM 位置变了。按 `wrapper.querySelector` 之类以挂载根为基准取浮层
233
+ 节点的代码要改从 `document` 取。
234
+
235
+ ## 遮罩式浮层并到同一档层号
236
+
237
+ `--xh-z-drawer` 删除,`--xh-layer-drawer` 与 `--xh-layer-modal` 解析到同一个值。
238
+
239
+ 原先抽屉 1000 低于对话框 1100,而两者都在同一个栈上下文里,纯靠数字定序:从对话框里
240
+ 拉出抽屉时,抽屉连同自己的遮罩一起沉在对话框遮罩底下,用户只看到画面又暗一层、什么都
241
+ 没出现,而焦点已经陷进看不见的面板。反方向是对的,所以这是只在一个方向上炸的组合。
242
+ 并档之后先后交给 portal 顺序决定,与对话框套对话框的现有行为一致。
243
+
244
+ **破坏性**:`--xh-z-drawer` 这个名字没有了。改用 `--xh-layer-drawer`。
245
+
246
+ ## 背景失活改走祖先链
247
+
248
+ `hideOutside` 此前只遍历 body 直接子元素,判据是「这个子元素包含 target 就整块放行」。
249
+ WC 适配器的浮层长在作者写它的位置,应用只要有一层根容器(`#app` 之类)就会因包含浮层
250
+ 被整块豁免——模态对话框身后的整个应用对读屏依然完全可遍历,不认外点关闭的
251
+ `alertdialog` 更是完全可点。改成沿每个 target 到 body 的祖先链逐层罩住其余兄弟。
252
+
253
+ `data-xh-inert-exempt` 的语义随之扩大:带标记的元素及其后代不被罩住,**其祖先只递归、
254
+ 不整块罩住**。通知队列因此在任意嵌套深度都能保持可点,外点判定也一并豁免(点通知不再
255
+ 把模态关掉)。
256
+
257
+ ## 其余
258
+ - `--xh-editable-preview-line-height` 删除,改用 `--xh-editable-preview-min-h`:预览态
259
+ 原先拿行高冒充高度,实测比同组件的编辑态高 2px,切换时跳一下。
260
+ - tooltip 与 navigation-menu 入层栈,Escape 不再连它们下面的对话框一起关掉。
261
+ - 定位引擎新增 size 中间件,回报可用空间与锚点宽度;菜单族补上高度上限与内部滚动。
262
+ - 包含块判定补齐 `translate` / `rotate` / `scale` 独立属性与 `backdrop-filter`。
263
+ - 滚动锁补滚动条补偿与滚动根探测。
264
+
265
+ - 9548330: 新增 `scrollbar` 组件:自绘滚动条,挂在**任意一个**滚动容器上——表格的滚动盒、虚拟滚动的视口、随手一个 `overflow: auto` 的 div 都行,不必是本组件的后代。此前这套东西焊在 `scroll-area` 里,只有连视口带内容一起交出去的场景用得上。
266
+
267
+ 解剖 `root` / `track` / `thumb` 三层必需、`corner` 可选(横竖两条同时摆着时写在其中一条里补交叉口,配合 `gutter` 让两条各自让出那一格);四种露面时机(`auto` / `always` / `scroll` / `hover`)带收起延时;拖滑块、点轨道跳转、RTL 双向换算、滑块像素下限、成段的 `scroll-start` / `scroll-end` 与 `drag-start` / `drag-end` 都在库里。`focusable` 打开后滑块进 Tab 序、报 `role="scrollbar"` 与三个 `aria-value*`,方向键 / 翻页键 / Home / End 可用;缺省不进 Tab 序也对读屏隐藏——滚动本身由滚动容器报,同一件事没必要报两遍。触屏(粗指针)上默认交给原生滚动,整条不画并带 `data-native`,`forceVisible` 打开才画。收起不再打 `hidden`,而是 `data-state=hidden` 由皮肤淡出(`visibility` 随退场播完才收),露出同样淡入;根上另有 `data-hover` 标指针在不在这一片。
268
+
269
+ **`scroll-area` 改由 `scrollbar` 组装。** 滚动区不再有自己的机器:它是视口加两条 scrollbar——`scrollbar` 角色节点是那条滚动条的挂载点、同时充当它的根,里面照 scrollbar 的写法摆 `track` / `thumb` / `corner`(戴 `data-scope="scrollbar"`),显隐、拖动、键盘、几何、触屏原生、淡入淡出全是 scrollbar 那一套,两个组件共用一份滚动条。Vue 新增 `XhScrollAreaTrack`;交叉口 `corner` 改写在竖条的挂载点里,两条都显形时才露;`scroll-area` 新增 `size` / `forceVisible`;视口的占道改打在视口自己身上(`data-lane-vertical` / `data-lane-horizontal`),不再依赖 `:has()`。原 `--xh-scroll-area-thumb-*` / `-bar-*` / `-corner-bg` 那几个槽随之归到 `--xh-scrollbar-*` 名下;`scrollAreaMachine` / `ScrollAreaSchema` / `SCROLL_AREA_*` 导出不再有,连接层改收两台 scrollbar 机器与 props(`scrollAreaScrollbarProps` 给出每台的 props)。挂了自绘滚动条的容器带 `data-xh-scrollbar`(挂在它身上的条数),皮肤据此藏掉原生滚动条的外观——表格放进滚动区即可滚(吸顶表头与吸附列钉在视口上),虚拟滚动的视口给个 id 用 `controls` 挂上即可。
270
+
271
+ 滚动容器换了会自动把监听挪过去(`scrollable` / `controls` 指向另一个节点、或条件渲染的容器重建);查不到时投一条 `scrollbar.missing-scrollable` 诊断,不静默,容器后到时调一次 `api.measure()` 即接上。容器里内容长短变了会自动重量(`MutationObserver` 盯着子树,一拍内合并成一次),量不到的场合另有 `api.measure()`。
272
+
273
+ - 35c9b65: 四家分段控件(date-field · time-field · date-picker · time-picker)的盒内布局统一。
274
+
275
+ **解剖新增 `segment-group`**:包住全部段位与作者写在段间的分隔符。date-field / time-field /
276
+ time-picker 三家新增这个部件,date-picker 已有的分段容器 `input` 改名为它——四家从此同名同职。
277
+ time-picker 的 `input` 仍是段位本身(多实例),语义不动。
278
+
279
+ 破坏性改动:
280
+
281
+ - `date-picker` 的 `input` 部件改名 `segment-group`,不留别名。
282
+ - `getInputProps` → `getSegmentGroupProps`;`DatePickerInputProps` → `DatePickerSegmentGroupProps`。
283
+ - Vue `XhDatePickerInput` → `XhDatePickerSegmentGroup`。
284
+ - WC `@csspart input` → `@csspart segment-group`(作者标记写 `data-xh-part="segment-group"`)。
285
+ - `--xh-time-field-segment-fg-placeholder` → `--xh-time-field-placeholder-fg`;
286
+ `--xh-time-picker-segment-fg-placeholder` → `--xh-time-picker-placeholder-fg`。
287
+ - `--xh-time-picker-column-max-h` → `--xh-time-picker-column-h`(列改定高)。
288
+ - `--xh-date-picker-content-p` → `--xh-date-picker-content-py` / `-px`;
289
+ `--xh-time-picker-content-p` → `--xh-time-picker-content-py` / `-px`。
290
+
291
+ 作者要把段位与分隔符挪进 `segment-group` 里,清空钮与展开钮留在 `control` 直属:
292
+
293
+ ```html
294
+ <div data-xh-part="control">
295
+ <div data-xh-part="segment-group">
296
+ <span data-xh-part="segment"></span>
297
+ <span>:</span>
298
+ <span data-xh-part="segment"></span>
299
+ </div>
300
+ <button data-xh-part="clear-trigger"></button>
301
+ </div>
302
+ ```
303
+
304
+ 行为与外观:
305
+
306
+ - 尾部按钮一律靠框内末端,靠 `segment-group` 的 `flex: 1 1 auto` 顶;
307
+ time-field 清空钮与 time-picker 展开钮的 `margin-inline-start: auto` 删掉。
308
+ - 四家 `control` 的 `gap` / `block-size` / `padding-inline` / `min-inline-size` 逐条同值,
309
+ `gap` 随尺寸档走 `--xh-control-gap-sm/md/lg`。
310
+ - 时间列定高:`time-picker` 的 `column` 与 `date-picker` 的 `time-column` 走 `--xh-viewport-h-sm`,
311
+ 两家的快捷选项列同档;两家浮层补上最大高度。
312
+ - 段位内衬统一 `--xh-space-1`;标题不再写 `cursor`;`:focus-within` 一律带 `:not([data-disabled])`;
313
+ time-picker 聚焦时补画聚焦环;图标尺寸随尺寸档走 `--xh-glyph-size-sm/md/lg`。
314
+
315
+ - bbc3431: select 浮层多出一个底部操作区:「新建」「全选」这类按钮终于有地方放了。
316
+
317
+ 原来放不进去有两条硬理由,都不是样式能绕的:`content` 既是 `role="listbox"`
318
+ (而 listbox 只许拥有 option 与 group,塞按钮进去是违规),又是那个 `overflow-y: auto` 的滚动容器
319
+ (放进去的按钮会跟着条目滚走)。所以这次把两件事拆开:
320
+
321
+ - **`content` 退成浮层外壳** —— 描边、底色、阴影、整体尺寸与键盘收口归它,它自己不滚。
322
+ - **新增 `list` 部件** —— `role="listbox"`、条目的拥有关系、滚动与那个「无锚点时兜底的 Tab 位」全在它身上。
323
+ - **新增 `footer` 部件** —— `list` 的兄弟。因此它既不进列表框的拥有关系,方向键与连打检索也走不到它,
324
+ 条目多到要滚时它仍贴在下沿不动。
325
+
326
+ **破坏性变更(alpha 期)**:条目现在要写在 `list` 里。
327
+
328
+ - Vue:`<XhSelectContent>` 与条目之间加一层 `<XhSelectList>`;底部操作区用新增的 `<XhSelectFooter>`。
329
+ 只传 `collection`、不写插槽的那条路由组件自己铺好,一个字都不用改。
330
+ - Web Components:`<div data-xh-part="content">` 里加一层 `<div data-xh-part="list">` 包住条目。
331
+ `list` 已列进 `requiredParts`,忘了写会在诊断通道上报 `wc.missing-part`,不会静默丢掉列表框语义。
332
+ - `trigger` 的 `aria-controls` 随之改指 `list`(它才是那个列表框)。
333
+
334
+ - 35c9b65: 相似组件与组合组件的视觉、动效、行为收成一套口径(`开发设计/UI.VisualConsistency.Contract.md`)。
335
+
336
+ **盒的定义统一了。** 此前 16 个输入 / 选择控件有三种「盒」:9 家由 `control` 画描边与底、5 家由 `trigger`(一个 `<button>`)当盒、2 家由 `input` 自画。盒是 button 的那 5 家(select · cascader · tree-select · popselect · color-picker)没法把清空钮放进框里,只能贴在框外——这就是「清空钮位置不统一」的总根因。现在判据只有一条:**解剖里有 `control` 就是盒**,`trigger` 退化成盒内那颗 `flex: 1 1 auto; border: 0; background: transparent` 的按钮,聚焦环改画在 `control:focus-within` 上。cascader / tree-select / popselect / color-picker / text-field 的解剖新增 `control` 部件。
337
+
338
+ **尾部按钮一律在框内最右。** 盒内布局恒为「内容区 `flex: 1` → 尾钮组 `flex: none`」。段位并排、没有单一容器的四家(date-field · time-field · date-picker · time-picker)新增 `segment-group` 部件把段位与分隔符包起来当内容区(date-picker 原有的 `input` 分段容器改名 `segment-group`,四家从此同名同职),`margin-inline-start: auto` 那套 hack 删掉。行内动作钮(清空 / 展开 / 明暗切换 / 加减)一律 `--xh-control-action-size` 方钮——number-field 的加减钮与 password-input 的明暗钮此前是「贴边的控件高钮」。
339
+
340
+ **并排成对的面板定高。** 新增 `--xh-viewport-h-sm/md/lg`(12/16/24rem,compact 同比例收)。transfer 两侧列表此前是 `min 8rem / max 16rem`,条目搬走后整个组件跟着变矮——现在定高 `--xh-viewport-h-md`,左右等高、空侧也占满。cascader 的列、date-picker / time-picker 的时间列同样定高;单个浮层面板仍内容驱动,但补上了此前缺失的高度上限。
341
+
342
+ **菜单族三家逐条同值。** `menu` / `menubar` / `context-menu` 共用同一台机器,皮肤却各写各的:menubar 根本没有 `item[data-state='open']` 这条规则,所以「发送到…」展开时不像 menu 那样加粗高亮。现在条目内衬 / 字号 / 圆角 / 行高 / 展开态 / 高亮态 / `content` 外观 / `separator` / `group-label` 全族同值,menu 补齐 `group` / `group-label` / `separator` 部件,子菜单箭头走字形令牌。navigation-menu 与 side-nav 的弹出面板按同族口径归队。
343
+
344
+ **浮层面板与输入族小件归队。** `content` 一律双槽内衬 + 族档 min-w / max-w;cascader 的 48rem、color-picker 的 15rem、tour 的 22rem 等裸值改令牌(新增 `--xh-overlay-max-w-xl`);label 颜色与间距、图标尺寸随档、聚焦环私有槽(invalid 时变红)、`:focus-within` 的禁用守卫、disabled / readonly 的三样齐——逐条统一。password-input 的明暗钮用上了新的 `--xh-glyph-mark-eye` / `-eye-off` 字形令牌。
345
+
346
+ **门禁**:`check-control-box`(盒结构 12 条判据)、`check-panel-height`(面板高度只走滚动面令牌、并排面板必须定高)、`check-family-parity`(菜单族 / 分段族 / 下拉族 / 气泡族逐条同值)。
347
+
348
+ 公开面:五家 `--xh-<c>-trigger-*` → `--xh-<c>-control-*` 槽改名、date-picker 的 `input` 部件与 `XhDatePickerInput` 组件改名 `segment-group` / `XhDatePickerSegmentGroup`、`--xh-hover-card-font-size` 与 transfer 的 `-list-min-h` / `-list-max-h` 删除,共 43 项,基线已推。
349
+
350
+ - 520b847: 周序号成为一等部件 `week-number`,不再由使用者自己拼一列出来。
351
+
352
+ 上一版只把数字算出来(`panel.weekNumbers`),列宽得作者用行内 `grid-template-columns` 自己撑,
353
+ 库不管它的皮——同一份东西在不同项目里会长得不一样,这不是组件库该留的样子。
354
+
355
+ - 解剖新增 `week-number`(可选部件,不写即不渲染),语义是这一行的表头(`role=rowheader`):
356
+ 在 `role=grid` 里,一行的标号本就该是 rowheader,而不是又一个可选的格子
357
+ - `getWeekNumberProps` / `getWeekNumberText` 两条,文字由两个适配器各自填,保证同构;
358
+ 表头那一格是占位、不带值,解析不了不抛、给空串占住列宽
359
+ - 皮肤接管列宽与字样:摆了周序号格的行自动让出行首一列
360
+ (`--xh-calendar-week-number-w`,默认 2.25rem),数字比日子小一号、颜色压下去、不跟着选中态走
361
+ - 新增 `XhCalendarWeekNumber` / `XhDatePickerWeekNumber`;WC 侧写
362
+ `<span data-xh-part="week-number" value="行首那天">` 即可
363
+
364
+ 选择器那条列宽规则写的是 `:not([hidden]):has(...)`——同特指度的规则谁在后面谁赢,
365
+ 不带这一道的话收起态会被这条 `display` 掀开(上一轮刚栽过一次,已有门禁拦着)。
366
+
367
+ ### Patch Changes
368
+
369
+ - 34bcedc: `custom-elements.json` 补上 `cssProperties` 与 `events` 的 `type`。
370
+
371
+ analyzer 自己吐不出这两样:覆盖槽的事实源在皮肤里,事件 detail 类型在元素源码的 notify 签名上。
372
+ 新增 `scripts/enrich-cem.mjs` 在 `cem analyze` 之后就地从两边补写——1945 条皮肤覆盖槽、
373
+ 122 个事件里的 118 个带上了 detail 类型(其余 4 个是 composer#stop 这类没有 detail 的事件)。
374
+ `pnpm --filter @xihan-ui/web-components cem` 的产出由 `gate:cem` 的 git diff 校验钉进流水线:
375
+ 改皮肤或改事件类型而不重跑,门禁当场失败。
376
+
377
+ - 7da1272: 废弃提示落地:五种没有 IDE 提示的介质在 dev 里经诊断通道发 `warn`。
378
+
379
+ 版本政策承诺过「dev 构建下经诊断通道发 warn」,此前一直未落地。现在 `@xihan-ui/kernel` 新增
380
+ 废弃登记表与探测:维护者 `registerDeprecation({ medium, match, message, replaceWith, until })` 登记
381
+ 一条,消费方的旧用法在 dev 里变成一条带迁移方向的诊断。
382
+
383
+ 五种介质与探测面:
384
+
385
+ - `css-var` / `layer` / `selector` —— 样式表(`<style>` 文本与 CSSOM,跨域样式表静默跳过)
386
+ - `attribute` —— DOM 里 `xh-*` 元素上的废弃 attribute(业务元素同名属性不误报)
387
+ - `part` —— 作者写的 `data-xh-part` 角色名,由 Web Components 适配器的部件契约校验带上下文投递
388
+
389
+ 两个适配器都在 dev 里自动启动探测(Vue 在第一个组件建机器时借路启动一次,Web Components 在
390
+ `defineXhElements()` 里启动),生产构建跳过;登记表为空时扫描器直接早退,零开销。同一废弃名
391
+ 无论命中多少条规则只报一次(通道去重)。登记表当前为空,发废弃时随 changeset 一起登记第一条。
392
+
393
+ - ed01a81: 框架元数据:名称、版本与运行时信息的单一事实源,与 XiHan.Framework 的 `XiHanMetadata` 同构。
394
+
395
+ `@xihan-ui/kernel/metadata` 子路径新增 `XIHAN_UI_METADATA` 与 `XIHAN_UI_VERSION`(与 Framework 的独立 Metadata 包同理,主入口保持结构原语,不背它的体积棘轮):
396
+
397
+ - **静态常量集中维护**:名称 / 显示名 / 版权 / 作者 / 组织 / 仓库 / 文档 / 许可证 / 关键词 /
398
+ 支持平台 / 适配器清单 / 标志 / 寄语,全部 `Object.freeze`。
399
+ - **版本从 package.json 派生**:`version` 与 `majorVersion` / `minorVersion` / `patchVersion` /
400
+ `prerelease` 自动解析,锁步发版下改版本只改 package.json 一处。
401
+ - **运行时信息**:`getRuntimeInfo()` 报 dev/prod 模式与 SSR 状态;两个适配器启动时用
402
+ `registerRuntimeHost()` 登记自己,元数据据此报出「运行在哪个适配器、什么版本」——
403
+ Framework 侧 EntryAssembly 概念在浏览器语境下的对应物。
404
+ - **输出**:`getMetadataSummary()` / `getMetadataDetails()` 返回格式化文本(宿主行如实报
405
+ 锁步一致性),`print` 版只在 dev 出声,生产静默。
406
+ - **启动横幅**:对齐 Framework 的 `XiHanApplicationBase`——引用即打印。适配器启动时
407
+ (Vue 首个组件建机器 / WC 注册元素)自动打一次 Logo + 摘要(整页一次、生产静默),
408
+ `setMetadataAutoPrint(false)` 可关。
409
+
410
+ 文档见新章节「框架元数据」(guide/metadata)。
411
+
412
+ - a321a50: 锁步版本检查:混装版本在 dev 里报 `core.version-mismatch`,不再只靠自觉。
413
+
414
+ 17 包同版本是硬承诺,但包管理器不会拦「vue alpha.2 + kernel alpha.3」这种跨包组合——
415
+ 类型对不上、同一个 `xh-` 标签被两个版本注册直接抛错,全部静默到运行时。现在 `@xihan-ui/kernel`
416
+ 导出自己的 `VERSION` 与 `checkLockstepVersion()`,两个适配器在 dev 启动时(与废弃探测同一次
417
+ 借路)拿自身版本比对,不一致经诊断通道发一条 warn,生产构建跳过。
418
+
419
+ - ac885c9: number-field 新增可选 `control` 部件:加减按钮叠进输入框内,与输入框成为视觉一体。
420
+
421
+ 此前加减钮与输入框是兄弟节点,受 HTML 约束进不了框内,只能三件并排。现在把输入框与两个按钮
422
+ 放进 `control` 部件,皮肤把描边、底色、聚焦环(改为 `:focus-within`)整体画在 control 上:
423
+ 框内 input 退成透明,减钮在左、加钮在右、输入框居中(顺序由作者模板决定),前后缀图标/文字
424
+ 直接流式插在 input 两侧,不用绝对定位;悬停/按下/贴边禁用沿用原有语义色。
425
+
426
+ - **Vue**:新增 `XhNumberFieldControl`;`data-disabled` / `data-readonly` / `data-invalid`
427
+ 三个状态属性由 connect 落到 control 上。
428
+ - **Web Components**:作者写 `<div data-xh-part="control">` 包裹即得同样的一体式。
429
+ - **不写 control 时完全退回旧观感**:control 是可选部件,旧模板一行不改照常渲染,三档
430
+ variant / tone / size 与旧式并排布局一致。
431
+
432
+ 一致性测试的 fixture 改成一体的 control 结构,两个适配器的 conformance 同步通过。
433
+
434
+ - b04e182: number-field 新增 `parse` / `format`:千位分隔符、单位后缀这类带格式的数字,现在不用把组件拆开自己拼了。
435
+
436
+ `parse` 把显示串读成数(默认 `Number()`,`'12abc'` 判为非法),`format` 把数写回显示串(默认 `String()`)。
437
+ 两个方向必须互逆——`format` 出来的串要能被 `parse` 读回同一个数,否则按一下加号值就会漂。
438
+
439
+ 落点分得很清楚:
440
+
441
+ - **`parse` 管所有"读"**:步进、取端点、失焦规范化、`aria-valuenow`、`valueAsNumber`、贴边判定,
442
+ 全都从它拿数。读屏念的因此是数,不是那串带逗号的显示文本。
443
+ - **`format` 只管组件自己改写显示的那三处**:步进、取端点、失焦规范化。
444
+ 用户正在打字时一律不碰——中途补格式会打断光标位置。
445
+
446
+ 界仍按数比而不按串比,越界时先夹回区间再补格式。作者的 `parse` 返回了非数按 `NaN` 处理、
447
+ `format` 返回了非串退回 `String(value)`,坏的返回值不会顺着流进后续计算。
448
+
449
+ - 93fdcb8: pin-input 新增 `pattern`:每格接受哪些字符可以自己定,不再只有 numeric / alphabetic / alphanumeric 三档。
450
+
451
+ `pattern` 收一段正则源码,内部补上首尾锚与 `u` 标志后逐个字符整格匹配——作者写 `[0-9A-Fa-f]`
452
+ 就够,不必自己写锚点,代理对(emoji 这类)也匹得上。给了它就盖过 `type` 的准入表;
453
+ 写坏了(编不成正则)**退回 `type` 的准入表而不是放行一切**,也不抛。
454
+
455
+ 敲、粘贴、外部 `setValue` 三条写值的路都过同一份准入表。
456
+
457
+ `type` 保留原职:它仍然决定移动端弹哪种键盘。准入放宽到字母时记得把 `type` 一并改掉,
458
+ 否则弹的还是数字键盘、那几个字符敲不进来——这一条写进了 props 说明与示例。
459
+
460
+ - 8d6e450: 整洁度归队(统一性审计的最后一批)。
461
+
462
+ **令牌**:dialog / drawer 的宽度档提为 `--xh-overlay-sheet-w-sm/md/lg`(24/32/48rem)与 `--xh-overlay-drawer-w-sm/md/lg`(16/20/28rem),empty-state / result 的图标档提为 `--xh-glyph-size-xl/2xl/3xl/4xl`;`--xh-control-gap-lg` 此前与 md 恒等,改为 space-3(compact space-2);补 `--xh-fg-warning` / `--xh-fg-info`(与 success 同构)。tokens README 写明 px 与 rem 的口径,以及「单行控件本体的槽一律叫 control」。
463
+
464
+ **皮肤**:number-field 的 `--xh-number-field-input-h` 在 control 上用错部件名,改 `--xh-number-field-control-h`;spinner 三档归 glyph 尺寸族、anchor / pagination / steps / composer / menubar 的内衬对齐 control-px 阶梯;back-top / card / float-button / switch / dynamic-input 的阴影补使用者槽;timeline / typography / field / slider 的字面残留改令牌;30 处与令牌同值却不引令牌的兜底改引(15 处登记理由);checkbox-group / transfer 的指示符字形与 checkbox 同一配方。菜单与列表族的条目高亮只认 `[data-highlighted]`(菜单族此前还并挂 `:focus` / `:focus-visible`)。
465
+
466
+ **无障碍**:select 的触发器按 APG select-only combobox 打 `role=combobox` + `aria-haspopup=listbox` + `aria-controls`(popselect 是按钮式弹出保持 button);image-viewer 触发器补 `aria-controls`;83 处 `aria-hidden` 统一写布尔;iconOnly 按钮没有 `aria-label` / `aria-labelledby` 时开发模式提醒一次(Vue / WC 把作者写在根节点上的可及名转告连接层)。
467
+
468
+ **共享配方**:visually-hidden 的 9 条声明收成 headless 的 `VISUALLY_HIDDEN_STYLE`,六份 connect 引它;七份皮肤各自那份必须与 `visually-hidden.css` 逐条一致。
469
+
470
+ **门禁**:`check-literal-fallbacks`(兜底字面量与令牌同值即红)、`check-visually-hidden`、`check-tone-contrast`(自算 oklch → WCAG 对比度,六族 × 两主题 26 组配对,1 组已知例外登记理由)、`check-aria-shapes`(aria-hidden 字符串写法 / listbox 触发器角色);`check-elevation-role` 增「阴影必须带使用者槽」。
471
+
472
+ - bb47c3d: time-picker 的上午/下午在浮层里也成列:从此点得中,不必回到输入行敲。
473
+
474
+ 此前 12 小时制下浮层只排时分秒三列,上下午只有输入行里那一段能改——指针用户点开浮层,
475
+ 挑完时与分还得把手挪回段上,一次选值走两个地方。
476
+
477
+ - 列的单位与分段输入里的段同名同域(新增 `dayPeriod`),恒排在末位、只在 12 小时制下出现;
478
+ 两格写 `'00'` / `'01'`,与这一段在 `aria-valuenow` 上报的数同一个域,
479
+ 选中比对、写值换算于是全都复用现成的那条路,浮层里挑与段上按 a / p 落到同一个 `setTimeDayPeriod`。
480
+ - 新增 `getItemText`:格子上的文字改由它给,数字列还是格子自己的值,上下午列按 locale 译成
481
+ 「上午 / 下午」。两个适配器都改用它填文本,保证同构。
482
+ - 上下午列跟着 min / max 收窄:当前小时翻到另一半天即出界时,那一格不可选(与时列互为对方的裁剪条件)。
483
+ 这与段上按 a / p 的处置不同——段上照写只做越界标注,列里则直接裁掉,两条路本来的语义就不一样。
484
+ - 两端那一段的外角与浮层其余列一致;`granularity` 与它无关,`hour` 档也照排。
485
+
486
+ `TimePickerColumn` 因此带上了单位的类型参数(缺省仍是全集,写 `TimePickerColumn` 的地方不用改)。
487
+ date-picker 内嵌的时间面板恒为 24 小时制,用新增的 `DatePickerTimeUnit` 把「没有上下午那一列」写进类型里。
488
+
489
+ 顺带把 `custom-elements.json` 与 `public-surface.json` 重新生成:前者自 number-field 的
490
+ control 部件落地起就没跟着更新过,后者漏了 kernel 的两个子路径入口。
491
+
492
+ - Updated dependencies [906b712]
493
+ - Updated dependencies [e12e337]
494
+ - Updated dependencies [ff84a16]
495
+ - Updated dependencies [97cbb2a]
496
+ - Updated dependencies [a55c76e]
497
+ - Updated dependencies [089db90]
498
+ - Updated dependencies [ada8a01]
499
+ - Updated dependencies [1461cec]
500
+ - Updated dependencies [e2292bf]
501
+ - Updated dependencies [d0202b2]
502
+ - Updated dependencies [7da1272]
503
+ - Updated dependencies [0be028c]
504
+ - Updated dependencies [1b7a5f1]
505
+ - Updated dependencies [ed01a81]
506
+ - Updated dependencies [1e90ce6]
507
+ - Updated dependencies [a321a50]
508
+ - Updated dependencies [8d35702]
509
+ - Updated dependencies [ac885c9]
510
+ - Updated dependencies [b04e182]
511
+ - Updated dependencies [e31cc0a]
512
+ - Updated dependencies [d738f78]
513
+ - Updated dependencies [93fdcb8]
514
+ - Updated dependencies [516bd46]
515
+ - Updated dependencies [9548330]
516
+ - Updated dependencies [35c9b65]
517
+ - Updated dependencies [bbc3431]
518
+ - Updated dependencies [d0202b2]
519
+ - Updated dependencies [309feb2]
520
+ - Updated dependencies [8d6e450]
521
+ - Updated dependencies [bb47c3d]
522
+ - Updated dependencies [35c9b65]
523
+ - Updated dependencies [520b847]
524
+ - Updated dependencies [c2b9748]
525
+ - @xihan-ui/headless@1.0.0-alpha.3
526
+ - @xihan-ui/kernel@1.0.0-alpha.3
527
+ - @xihan-ui/motion@1.0.0-alpha.3
528
+ - @xihan-ui/behavior@1.0.0-alpha.3
529
+ - @xihan-ui/backgrounds@1.0.0-alpha.3
530
+ - @xihan-ui/position@1.0.0-alpha.3
531
+ - @xihan-ui/machine@1.0.0-alpha.3
532
+ - @xihan-ui/code-highlight@1.0.0-alpha.3
533
+
3
534
  ## 1.0.0-alpha.2
4
535
 
5
536
  ### Minor Changes