@xihan-ui/styles 2.0.0 → 3.0.0

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.
Files changed (156) hide show
  1. package/CHANGELOG.md +1328 -0
  2. package/README.md +6 -1
  3. package/component-tokens.d.ts +505 -111
  4. package/components.tokens.json +34750 -26291
  5. package/css/accordion.css +39 -13
  6. package/css/alert.css +61 -3
  7. package/css/anchor.css +49 -11
  8. package/css/approval.css +124 -84
  9. package/css/avatar-group.css +1 -1
  10. package/css/avatar.css +13 -5
  11. package/css/back-top.css +63 -44
  12. package/css/badge.css +63 -13
  13. package/css/bar-code.css +1 -1
  14. package/css/breadcrumb.css +63 -4
  15. package/css/button-group.css +5 -5
  16. package/css/button.css +69 -21
  17. package/css/calendar-picker.css +27 -8
  18. package/css/calendar-range-picker.css +48 -11
  19. package/css/card.css +116 -2
  20. package/css/carousel.css +153 -48
  21. package/css/cartesian-chart.css +830 -0
  22. package/css/cascader.css +184 -70
  23. package/css/checkbox-group.css +69 -99
  24. package/css/checkbox.css +21 -54
  25. package/css/citation.css +470 -0
  26. package/css/clipboard.css +23 -66
  27. package/css/code-view.css +103 -8
  28. package/css/collapsible.css +37 -11
  29. package/css/color-field.css +18 -0
  30. package/css/color-picker.css +57 -62
  31. package/css/color-slider.css +26 -19
  32. package/css/color-swatch-picker.css +8 -6
  33. package/css/combobox.css +82 -37
  34. package/css/command.css +48 -48
  35. package/css/context-menu.css +43 -28
  36. package/css/date-field.css +23 -0
  37. package/css/date-picker.css +57 -24
  38. package/css/date-range-picker.css +301 -14
  39. package/css/description.css +17 -1
  40. package/css/descriptions.css +43 -1
  41. package/css/dialog.css +99 -43
  42. package/css/diff-view.css +101 -16
  43. package/css/download-trigger.css +46 -80
  44. package/css/drawer.css +168 -133
  45. package/css/editable.css +19 -0
  46. package/css/empty-state.css +8 -7
  47. package/css/field-array.css +36 -0
  48. package/css/field.css +17 -19
  49. package/css/fieldset.css +1 -1
  50. package/css/file-upload.css +126 -136
  51. package/css/flex.css +324 -8
  52. package/css/float-button.css +168 -41
  53. package/css/floating-panel.css +59 -27
  54. package/css/form.css +26 -20
  55. package/css/funnel-chart.css +106 -0
  56. package/css/graph-chart.css +205 -0
  57. package/css/grid-list.css +235 -0
  58. package/css/grid.css +252 -1
  59. package/css/heatmap.css +119 -36
  60. package/css/hierarchy-chart.css +298 -0
  61. package/css/hover-card.css +33 -18
  62. package/css/icon.css +100 -0
  63. package/css/image-cropper.css +34 -8
  64. package/css/image-viewer.css +169 -26
  65. package/css/image.css +23 -4
  66. package/css/infinite-scroll.css +2 -2
  67. package/css/input-group.css +13 -15
  68. package/css/json-viewer.css +55 -7
  69. package/css/kbd.css +1 -1
  70. package/css/layout.css +71 -21
  71. package/css/liquid.css +106 -0
  72. package/css/list.css +2 -2
  73. package/css/listbox.css +72 -23
  74. package/css/loading-bar.css +27 -13
  75. package/css/log.css +131 -35
  76. package/css/markdown-stream.css +1 -1
  77. package/css/marquee.css +163 -7
  78. package/css/matrix-code.css +1 -1
  79. package/css/mention.css +35 -21
  80. package/css/menu.css +40 -28
  81. package/css/menubar.css +42 -28
  82. package/css/message-feed.css +174 -53
  83. package/css/navigation-menu.css +177 -18
  84. package/css/notification.css +431 -110
  85. package/css/number-field.css +22 -0
  86. package/css/page-header.css +4 -2
  87. package/css/pagination.css +129 -29
  88. package/css/password-input.css +40 -8
  89. package/css/pie-chart.css +247 -0
  90. package/css/popconfirm.css +50 -58
  91. package/css/popover.css +55 -21
  92. package/css/progress.css +308 -10
  93. package/css/prompt-input.css +37 -1
  94. package/css/question-flow.css +104 -64
  95. package/css/radar-chart.css +233 -0
  96. package/css/radio-group.css +372 -14
  97. package/css/rating.css +25 -27
  98. package/css/reasoning.css +62 -55
  99. package/css/reset.css +1 -1
  100. package/css/resizable.css +6 -1
  101. package/css/sankey-chart.css +174 -0
  102. package/css/scroll-area.css +32 -0
  103. package/css/scrollbar.css +1 -1
  104. package/css/select.css +76 -59
  105. package/css/side-nav.css +177 -30
  106. package/css/signature-pad.css +23 -8
  107. package/css/skeleton.css +13 -14
  108. package/css/slider.css +39 -17
  109. package/css/sortable.css +38 -8
  110. package/css/sparkline.css +164 -0
  111. package/css/spinner.css +50 -22
  112. package/css/splitter.css +8 -2
  113. package/css/statistic.css +10 -0
  114. package/css/steps.css +257 -38
  115. package/css/switch.css +30 -55
  116. package/css/table.css +168 -128
  117. package/css/tabs.css +243 -31
  118. package/css/tag-group.css +65 -37
  119. package/css/tag.css +55 -14
  120. package/css/tags-input.css +40 -3
  121. package/css/text-field.css +19 -0
  122. package/css/time-field.css +20 -1
  123. package/css/time-picker.css +44 -17
  124. package/css/time-range-picker.css +45 -18
  125. package/css/timeline.css +1 -1
  126. package/css/toggle-group.css +8 -8
  127. package/css/toggle.css +6 -5
  128. package/css/tool-call.css +64 -56
  129. package/css/toolbar.css +105 -7
  130. package/css/tooltip.css +18 -7
  131. package/css/tour.css +49 -21
  132. package/css/transfer.css +104 -81
  133. package/css/tree-select.css +235 -58
  134. package/css/tree.css +240 -147
  135. package/css/truncate.css +55 -12
  136. package/css/typography.css +93 -0
  137. package/css/virtualizer.css +57 -1
  138. package/css/watermark.css +23 -0
  139. package/family/action-control.css +14 -5
  140. package/family/chart.css +480 -0
  141. package/family/check-mark.css +94 -0
  142. package/family/choice-card.css +97 -0
  143. package/family/collection-item.css +70 -27
  144. package/family/field-chrome.css +1 -12
  145. package/family/loading-ring.css +95 -0
  146. package/family/material.css +72 -0
  147. package/family/menu-choice.css +56 -0
  148. package/family/motion.css +208 -11
  149. package/family/tag-list.css +59 -0
  150. package/index.css +23363 -14091
  151. package/index.unlayered.css +23198 -13922
  152. package/package.json +20 -8
  153. package/css/gradient-text.css +0 -91
  154. package/css/icon-wrapper.css +0 -81
  155. package/css/segmented.css +0 -280
  156. package/css/toast.css +0 -499
@@ -30,8 +30,8 @@
30
30
  /* 形态的落点:没写 data-variant 时这十支保持缺省档的取值,段的规则读的是
31
31
  「使用者令牌 → 这十支 → 语义令牌」三级,使用者令牌永远排在形态之前。
32
32
  未选中那五支管段的壳,选中那五支管当前值那一段。
33
- 缺省档(subtle)的段坐在自己的淡底面上,悬停 200 → 按下 300(§7.2 淡底承载);
34
- 选中段是无滑块开关(§7.3):品牌淡底 + 淡底前景,悬停 20% → 按下 28% */
33
+ 缺省档(subtle)的段坐在自己的淡底面上,悬停 200 → 按下 300(淡底承载);
34
+ 选中段是无滑块开关:品牌淡底 + 淡底前景,悬停 20% → 按下 28% */
35
35
  --xh-_toggle-group-item-bg: var(--xh-bg-subtle);
36
36
  --xh-_toggle-group-item-bg-hover: var(--xh-bg-subtle-hover);
37
37
  --xh-_toggle-group-item-bg-active: var(--xh-bg-subtle-active);
@@ -96,7 +96,7 @@
96
96
  --xh-_toggle-group-item-highlight-on: none;
97
97
  }
98
98
 
99
- /* outline 与 ghost 的段坐在画布上:悬停 100 → 按下 200(§7.2 白底承载) */
99
+ /* outline 与 ghost 的段坐在画布上:悬停 100 → 按下 200(白底承载) */
100
100
  [data-scope='toggle-group'][data-part='root'][data-variant='outline'] {
101
101
  --xh-_toggle-group-item-bg: transparent;
102
102
  --xh-_toggle-group-item-bg-hover: var(--xh-_tone-subtle, var(--xh-bg-subtle));
@@ -215,18 +215,18 @@
215
215
  font-weight: var(--xh-toggle-group-item-font-weight, var(--xh-text-label-weight));
216
216
  }
217
217
 
218
- /* 共边:后一段往回挪一个描边宽度,两条相邻的边重合成一条。
218
+ /* 共边只画一次:后一段不画起始边,由前一段的末端边承担。墨色描边半透明,两条重合会加深。
219
219
  方向跟着 data-orientation 走,横排收 inline 轴、竖排收 block 轴 */
220
220
  [data-scope='toggle-group'][data-part='root'][data-orientation='horizontal']
221
221
  > [data-scope='toggle-group'][data-part='item']
222
222
  + [data-scope='toggle-group'][data-part='item'] {
223
- margin-inline-start: calc(-1 * var(--xh-stroke-thin));
223
+ border-inline-start-width: 0;
224
224
  }
225
225
 
226
226
  [data-scope='toggle-group'][data-part='root'][data-orientation='vertical']
227
227
  > [data-scope='toggle-group'][data-part='item']
228
228
  + [data-scope='toggle-group'][data-part='item'] {
229
- margin-block-start: calc(-1 * var(--xh-stroke-thin));
229
+ border-block-start-width: 0;
230
230
  }
231
231
 
232
232
  /* 两端圆角用逻辑角属性写,rtl 与竖排都跟着换边,不必另写一套。
@@ -258,7 +258,7 @@
258
258
 
259
259
  /* 选中态:单选是 role=radio + aria-checked,多选是原生按钮 + aria-pressed,
260
260
  两套 ARIA 各出一半,样式一条都对不上——只有 data-state 是两种模式共同的出口。
261
- 无滑块开关(§7.3):品牌淡底 + 淡底前景,悬停 20% → 按下 28%,三态都经桥接槽交给家族画;
261
+ 无滑块开关:品牌淡底 + 淡底前景,悬停 20% → 按下 28%,三态都经桥接槽交给家族画;
262
262
  用哪族颜色由 data-tone 决定:语气槽沿继承流下来,root 自己写了 tone 算、
263
263
  整组落在语气容器里也算;没有语气就退回品牌配色,与不接语气时逐值相同。
264
264
  使用者令牌排在语气之前:写了组件槽就以它为准。
@@ -270,7 +270,7 @@
270
270
  --xh-action-bg-focus-visible: var(--xh-toggle-group-item-bg-on, var(--xh-_toggle-group-item-bg-on));
271
271
  --xh-action-bg-disabled: var(
272
272
  --xh-toggle-group-item-bg-on-disabled,
273
- color-mix(in oklab, var(--xh-_toggle-group-item-bg-on) 50%, var(--xh-bg-muted))
273
+ color-mix(in oklab, var(--xh-_toggle-group-item-bg-on) 50%, var(--xh-bg-muted-opaque))
274
274
  );
275
275
  --xh-action-fg-rest: var(--xh-toggle-group-item-fg-on, var(--xh-_toggle-group-item-fg-on));
276
276
  --xh-action-fg-hover: var(--xh-toggle-group-item-fg-on, var(--xh-_toggle-group-item-fg-on));
package/css/toggle.css CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  /* 未按下的四档形态由家族形态矩阵按 data-xh-action-variant 给出(缺省 subtle 由连接层显式投影;solid 未按下时
16
16
  投 ghost,只在按下时才是品牌实心);公开槽桥接到矩阵之前:使用者槽 → 形态矩阵 → 家族缺省。
17
- 按下(on)是 §7.3 无滑块开关的选中面:品牌淡底 12 → 悬停 20 → 按压 28,前景 fg-on-brand-subtle,
17
+ 按下(on)是无滑块开关的选中面:品牌淡底 12 → 悬停 20 → 按压 28,前景 fg-on-brand-subtle,
18
18
  私有槽在下面的 data-state='on' 块里接到桥接槽上。 */
19
19
  [data-scope='toggle'][data-part='root'] {
20
20
  --xh-_toggle-bg-on: var(--xh-toggle-bg-on, var(--xh-_tone-subtle, var(--xh-bg-brand-subtle)));
@@ -34,10 +34,11 @@
34
34
  );
35
35
  --xh-_toggle-fg-on: var(--xh-toggle-fg-on, var(--xh-_tone-fg, var(--xh-fg-on-brand-subtle)));
36
36
  --xh-_toggle-border-on: var(--xh-toggle-border-on, transparent);
37
- /* 禁用同时降级前景与表面,不靠 opacity;选中且禁用时底色掺一半中性面,选中信息不丢。 */
37
+ /* 禁用同时降级前景与表面,不靠 opacity;选中且禁用时底色掺一半中性面,选中信息不丢。
38
+ 掺的是淡底的不透明档:墨色淡底半透明,掺进去整块面会跟着变半透明 */
38
39
  --xh-_toggle-bg-on-disabled: var(
39
40
  --xh-toggle-bg-on-disabled,
40
- color-mix(in oklab, var(--xh-_toggle-bg-on) 50%, var(--xh-bg-subtle))
41
+ color-mix(in oklab, var(--xh-_toggle-bg-on) 50%, var(--xh-bg-subtle-opaque))
41
42
  );
42
43
  --xh-_toggle-fg-on-disabled: var(--xh-toggle-fg-on-disabled, var(--xh-_toggle-fg-on));
43
44
  --xh-action-bg-rest: var(--xh-toggle-bg, var(--xh-_action-variant-bg-rest));
@@ -97,7 +98,7 @@
97
98
  --xh-action-border-disabled: var(--xh-_toggle-border-on);
98
99
  }
99
100
 
100
- /* 使用者的 --xh-toggle-shadow 只落在按下面上:矩阵各态无影,淡底与阴影互斥(§5.3) */
101
+ /* 使用者的 --xh-toggle-shadow 只落在按下面上:矩阵各态无影,淡底与阴影互斥 */
101
102
  [data-scope='toggle'][data-part='root'][data-state='on'] {
102
103
  --xh-action-shadow-rest: var(--xh-toggle-shadow, none);
103
104
  --xh-action-shadow-hover: var(--xh-toggle-shadow, none);
@@ -113,7 +114,7 @@
113
114
  [data-scope='toggle'][data-part='root'][data-variant='solid'][data-state='on'] {
114
115
  --xh-action-bg-disabled: var(
115
116
  --xh-toggle-bg-on-disabled,
116
- color-mix(in oklab, var(--xh-_action-variant-bg-rest) 50%, var(--xh-bg-subtle))
117
+ color-mix(in oklab, var(--xh-_action-variant-bg-rest) 50%, var(--xh-bg-subtle-opaque))
117
118
  );
118
119
  --xh-action-fg-disabled: var(--xh-toggle-fg-on-disabled, var(--xh-_action-variant-fg-rest));
119
120
  --xh-action-highlight-rest: var(--xh-_highlight-tone);
package/css/tool-call.css CHANGED
@@ -16,20 +16,20 @@
16
16
  --xh-tool-call-skin: 1;
17
17
  }
18
18
 
19
- /* 一张静态内容面:--xh-border-default 描边 + surface 底 + 无影(§5.3 边界只由描边承担);
19
+ /* 一张静态内容面:--xh-border-default 描边 + surface 底 + 无影(边界只由描边承担);
20
20
  审批位与详情区的内部分隔线走另一支 --xh-tool-call-divider(subtle)。
21
21
  卡片建出来时淡入并向上收一段,一屏若干张的错峰交给外层容器排 */
22
22
  [data-scope='tool-call'][data-part='root'] {
23
23
  /* 尺寸缺省档:不写 data-size 时的取值。三档都只写这三个私有槽,
24
24
  公开槽留在读处当首选,作者在祖先上设的覆盖才赢得过档位声明 */
25
- --xh-_tool-call-px: var(--xh-space-3);
26
- --xh-_tool-call-py: var(--xh-space-2);
25
+ --xh-_tool-call-px: var(--xh-space-4);
26
+ --xh-_tool-call-py: var(--xh-space-4);
27
27
  --xh-_tool-call-font-size: var(--xh-control-font-md);
28
28
 
29
29
  /* 影另落一份进私有槽给语气档:它要把影与左侧色条叠成一条 box-shadow,缺省无影写成零影占位 */
30
30
  --xh-_tool-call-shadow: var(--xh-tool-call-shadow, 0 0 0 transparent);
31
31
 
32
- /* 作者塞进指示符里的图标与皮肤画的兜底字形同一把尺:md 档(§6.5),开关上另按家族档取值 */
32
+ /* 作者塞进指示符里的图标与皮肤画的兜底字形同一把尺:md 档,开关上另按家族档取值 */
33
33
  --xh-icon-size: var(--xh-tool-call-icon-size, var(--xh-glyph-size-md));
34
34
 
35
35
  display: block;
@@ -38,7 +38,11 @@
38
38
  border-radius: var(--xh-tool-call-radius, var(--xh-shape-surface));
39
39
  background: var(--xh-tool-call-bg, var(--xh-bg-surface));
40
40
  box-shadow: var(--xh-tool-call-shadow, none);
41
- animation: xh-tool-call-enter var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong) both;
41
+ }
42
+
43
+ /* 卡片出现时滑入;落在首帧就在的列表条目里(历史消息)时直接呈现,不跟着整屏一起入场 */
44
+ [data-scope='tool-call'][data-part='root']:not([data-scope][data-part='item'][data-instant] *) {
45
+ animation: xh-item-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong) both;
42
46
  }
43
47
 
44
48
  /* 上面声明的 display 会盖掉 UA 的 [hidden]{display:none},这里补回 */
@@ -49,7 +53,7 @@
49
53
  /* —— 形态 —— */
50
54
  /* 缺省档即 outline,写在上面那条基础规则里 */
51
55
  /* 底色分区:描边让位给底色,嵌在别人的面里时不再多一圈线;
52
- 淡底承载面向开关下发 hover 200 → pressed 300(§7.2) */
56
+ 淡底承载面向开关下发 hover 200 → pressed 300 */
53
57
  [data-scope='tool-call'][data-part='root'][data-variant='subtle'] {
54
58
  --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
55
59
  --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
@@ -84,7 +88,7 @@
84
88
  }
85
89
 
86
90
  /* 开关铺满一行,盒型、悬停 / 按下 / 禁用面由 Action Control 的 disclosure-trigger 档给(ghost 形态:
87
- 白底承载 hover 100 → pressed 200,按下只换面不缩放,§9.2);这里只把使用者槽映射到桥接槽:
91
+ 白底承载 hover 100 → pressed 200,按下只换面不缩放);这里只把使用者槽映射到桥接槽:
88
92
  圆角归零贴住卡边,内衬与字号沿用卡片的档位(不取 profile 的 md 档内衬,几何不变),
89
93
  字形按开关自己的档位取 --xh-_action-profile-glyph-size */
90
94
  [data-scope='tool-call'][data-part='trigger'] {
@@ -111,8 +115,12 @@
111
115
  align-items: center;
112
116
  justify-content: center;
113
117
  color: var(--xh-tool-call-indicator-fg, var(--xh-fg-subtle));
114
- /* 与详情展开同时长同曲线:箭头先转完、内容后到位会像是两件事 */
115
- transition: rotate var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
118
+ }
119
+
120
+ /* 与详情开合同时长:箭头先转完、内容后到位会像是两件事。收起取 collapse 档,展开(下面的打开态)取 expand 档。
121
+ 首帧就在的朝向直接呈现(data-instant),第一次开合起才转 */
122
+ [data-scope='tool-call'][data-part='indicator']:not([data-instant]) {
123
+ transition: rotate var(--xh-motion-duration-collapse) var(--xh-motion-ease-enter-strong);
116
124
  }
117
125
 
118
126
  /* 没写内容就由皮肤画;作者往部件里塞了自己的图形,这条规则即不命中 */
@@ -137,6 +145,10 @@
137
145
  rotate: 90deg;
138
146
  }
139
147
 
148
+ [data-scope='tool-call'][data-part='indicator'][data-state='open']:not([data-instant]) {
149
+ transition: rotate var(--xh-motion-duration-expand) var(--xh-motion-ease-enter-strong);
150
+ }
151
+
140
152
  [dir='rtl'] [data-scope='tool-call'][data-part='indicator'] {
141
153
  rotate: 180deg;
142
154
  }
@@ -151,6 +163,8 @@
151
163
  overflow: hidden;
152
164
  flex: 1 1 auto;
153
165
  font-family: var(--xh-tool-call-label-font, var(--xh-font-family-mono));
166
+ /* 面级披露的触发条文字取标签角色,与 Accordion、Collapsible、Reasoning 同一档字重 */
167
+ font-weight: var(--xh-tool-call-label-font-weight, var(--xh-text-label-weight));
154
168
  text-overflow: ellipsis;
155
169
  white-space: nowrap;
156
170
  }
@@ -197,29 +211,31 @@
197
211
  display: none;
198
212
  }
199
213
 
200
- /* 三档落定的阶段收成药丸:淡底 + 同族深字。在跑的两档不带底,让扫光自己说话 */
201
- [data-scope='tool-call'][data-part='status'][data-state='awaiting-approval'],
202
- [data-scope='tool-call'][data-part='status'][data-state='output-available'],
203
- [data-scope='tool-call'][data-part='status'][data-state='output-error'] {
214
+ /* 三档落定的阶段收成状态 chip:几何与 Tag 的 sm 档同一把尺,淡底 + 同族可读字取连接层投影的语气。
215
+ 在跑的两档不带底,让扫光自己说话 */
216
+ [data-scope='tool-call'][data-part='status'][data-tone] {
204
217
  padding-block: var(--xh-tool-call-status-py, var(--xh-space-0_5));
205
- padding-inline: var(--xh-tool-call-status-px, var(--xh-space-2));
218
+ padding-inline: var(--xh-tool-call-status-px, var(--xh-space-1_5));
219
+ border: var(--xh-stroke-thin) solid transparent;
206
220
  border-radius: var(--xh-tool-call-status-radius, var(--xh-shape-pill));
221
+ font-weight: var(--xh-font-weight-medium);
222
+ line-height: var(--xh-control-indicator-md);
207
223
  }
208
224
 
209
- /* 各阶段的状态色:与语气轴分开走,语气是作者定的强调 */
225
+ /* 各阶段的覆盖槽仍按阶段给:作者可以单独改某一档 */
210
226
  [data-scope='tool-call'][data-part='status'][data-state='awaiting-approval'] {
211
- background: var(--xh-tool-call-status-bg-approval, color-mix(in oklab, var(--xh-fg-warning) 12%, var(--xh-bg-surface)));
212
- color: var(--xh-tool-call-status-fg-approval, color-mix(in oklab, var(--xh-fg-warning) 60%, var(--xh-fg-default)));
227
+ background: var(--xh-tool-call-status-bg-approval, var(--xh-_tone-subtle));
228
+ color: var(--xh-tool-call-status-fg-approval, var(--xh-_tone-fg));
213
229
  }
214
230
 
215
231
  [data-scope='tool-call'][data-part='status'][data-state='output-available'] {
216
- background: var(--xh-tool-call-status-bg-done, color-mix(in oklab, var(--xh-fg-success) 12%, var(--xh-bg-surface)));
217
- color: var(--xh-tool-call-status-fg-done, color-mix(in oklab, var(--xh-fg-success) 60%, var(--xh-fg-default)));
232
+ background: var(--xh-tool-call-status-bg-done, var(--xh-_tone-subtle));
233
+ color: var(--xh-tool-call-status-fg-done, var(--xh-_tone-fg));
218
234
  }
219
235
 
220
236
  [data-scope='tool-call'][data-part='status'][data-state='output-error'] {
221
- background: var(--xh-tool-call-status-bg-error, color-mix(in oklab, var(--xh-fg-danger) 12%, var(--xh-bg-surface)));
222
- color: var(--xh-tool-call-status-fg-error, color-mix(in oklab, var(--xh-fg-danger) 60%, var(--xh-fg-default)));
237
+ background: var(--xh-tool-call-status-bg-error, var(--xh-_tone-subtle));
238
+ color: var(--xh-tool-call-status-fg-error, var(--xh-_tone-fg));
223
239
  }
224
240
 
225
241
  /* 在跑的时候状态文字自己扫一道光:data-loading 此前在皮肤里没有任何表达,
@@ -237,7 +253,7 @@
237
253
  background-clip: text;
238
254
  color: transparent;
239
255
  -webkit-text-fill-color: transparent;
240
- animation: xh-tool-call-shimmer var(--xh-tool-call-shimmer-duration, var(--xh-shimmer-duration)) var(--xh-motion-ease-loop) infinite;
256
+ animation: xh-shimmer var(--xh-tool-call-shimmer-duration, var(--xh-motion-loop-shimmer)) var(--xh-motion-ease-loop) infinite;
241
257
  }
242
258
 
243
259
  /* 减少动效:整道光撤掉换回平色,"在跑"仍由状态文字本身表达——只停动画的话,
@@ -303,15 +319,14 @@
303
319
  border-block-start: var(--xh-stroke-thin) solid var(--xh-tool-call-divider, var(--xh-border-subtle));
304
320
  }
305
321
 
306
- /* 展开那一档才提前备好行高这条通道:属性随 data-state 一起消失,收起后不长期占着 */
307
- [data-scope='tool-call'][data-part='content'][data-state='open'] {
308
- will-change: grid-template-rows;
309
- animation: xh-disclosure-expand var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
322
+ /* 展开与收起只在开合时播:首帧就在的展开 / 收起直接呈现(data-instant) */
323
+ [data-scope='tool-call'][data-part='content'][data-state='open']:not([data-instant]) {
324
+ animation: xh-disclosure-expand var(--xh-motion-duration-expand) var(--xh-motion-ease-enter-strong);
310
325
  }
311
326
 
312
- /* 退场走 exit 档曲线(§9.4) */
313
- [data-scope='tool-call'][data-part='content'][data-state='closed'] {
314
- animation: xh-disclosure-collapse var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
327
+ /* 退场走 exit 档曲线 */
328
+ [data-scope='tool-call'][data-part='content'][data-state='closed']:not([data-instant]) {
329
+ animation: xh-disclosure-collapse var(--xh-motion-duration-collapse) var(--xh-motion-ease-exit) forwards;
315
330
  }
316
331
 
317
332
  [data-scope='tool-call'][data-part='input'],
@@ -338,20 +353,20 @@
338
353
 
339
354
  /* 尺寸档只改内衬与字号 */
340
355
  [data-scope='tool-call'][data-part='root'][data-size='sm'] {
341
- --xh-_tool-call-px: var(--xh-space-2);
342
- --xh-_tool-call-py: var(--xh-space-1);
356
+ --xh-_tool-call-px: var(--xh-space-3);
357
+ --xh-_tool-call-py: var(--xh-space-3);
343
358
  --xh-_tool-call-font-size: var(--xh-control-font-sm);
344
359
  }
345
360
 
346
361
  [data-scope='tool-call'][data-part='root'][data-size='md'] {
347
- --xh-_tool-call-px: var(--xh-space-3);
348
- --xh-_tool-call-py: var(--xh-space-2);
362
+ --xh-_tool-call-px: var(--xh-space-4);
363
+ --xh-_tool-call-py: var(--xh-space-4);
349
364
  --xh-_tool-call-font-size: var(--xh-control-font-md);
350
365
  }
351
366
 
352
367
  [data-scope='tool-call'][data-part='root'][data-size='lg'] {
353
- --xh-_tool-call-px: var(--xh-space-4);
354
- --xh-_tool-call-py: var(--xh-space-3);
368
+ --xh-_tool-call-px: var(--xh-space-5);
369
+ --xh-_tool-call-py: var(--xh-space-5);
355
370
  --xh-_tool-call-font-size: var(--xh-control-font-lg);
356
371
  }
357
372
 
@@ -362,35 +377,28 @@
362
377
  inset var(--xh-tool-call-tone-bar, var(--xh-stroke-thick)) 0 0 0 var(--xh-tool-call-tone-fg, var(--xh-_tone-soft, var(--xh-bg-brand))),
363
378
  var(--xh-_tool-call-shadow);
364
379
  }
365
- }
366
380
 
367
- @layer xihan.motion {
368
- /* 组件专属关键帧写在自己身上;共享的 disclosure 关键帧由 family/motion.css 提供。
369
- 幅度走令牌,减弱动效时由令牌层归零 */
370
- @keyframes xh-tool-call-enter {
371
- from {
372
- opacity: 0;
373
- translate: 0 var(--xh-motion-distance-md);
374
- }
375
-
376
- to {
377
- opacity: 1;
378
- translate: 0 0;
381
+ @media (forced-colors: active) {
382
+ /* 兜底字形是 mask 挖出来的一块底色,这一档里底色被系统换成 Canvas,字形跟着消失。
383
+ 字形退出强制换色、直接写系统色(不能取 currentColor:退出强制换色的伪元素读到的是被系统换掉之前的作者色):
384
+ 按钮面上取 ButtonText,悬停与按下时家族把按钮涂成 Highlight、字形换 HighlightText;
385
+ 禁用取 GrayText */
386
+ [data-scope='tool-call'][data-part='indicator']:empty::before {
387
+ forced-color-adjust: none;
388
+ background-color: ButtonText;
379
389
  }
380
- }
381
390
 
382
- /* 一道比字色亮的窄带从右扫到左。背景图比自身宽一倍,靠移动背景位置扫过去,
383
- 不动布局也不动 transform */
384
- @keyframes xh-tool-call-shimmer {
385
- from {
386
- background-position: 150% center;
391
+ [data-scope='tool-call'][data-part='trigger']:not([data-disabled]):not([data-loading]):is(:hover, :active, [data-pressed]) [data-scope='tool-call'][data-part='indicator']:empty::before {
392
+ background-color: HighlightText;
387
393
  }
388
394
 
389
- to {
390
- background-position: -50% center;
395
+ [data-scope='tool-call'][data-part='trigger'][data-disabled] [data-scope='tool-call'][data-part='indicator']:empty::before {
396
+ background-color: GrayText;
391
397
  }
392
398
  }
399
+ }
393
400
 
401
+ @layer xihan.motion {
394
402
  @media print {
395
403
  /* 打印:动画会被定格在任意一帧——转了一半的圈、扫到一半的微光。这里换成静止的表达,
396
404
  取值与减弱动效那一档相同。两档各写一块、不并进一条媒体查询列表:减弱动效另有一份
package/css/toolbar.css CHANGED
@@ -31,7 +31,8 @@
31
31
  --xh-_toolbar-root-bg: transparent;
32
32
  --xh-_toolbar-root-bg-disabled: transparent;
33
33
 
34
- /* 一行排不下就折行:条目宽度由各自的控件决定,硬撑一行会把整条顶出容器 */
34
+ /* 一行排不下就折行:条目宽度由各自的控件决定,硬撑一行会把整条顶出容器。
35
+ 放了「更多」钮时改为收纳,见下方收纳一节 */
35
36
  display: flex;
36
37
  flex-wrap: wrap;
37
38
  align-items: center;
@@ -44,7 +45,7 @@
44
45
  color: var(--xh-toolbar-fg, var(--xh-fg-default));
45
46
  /* 整条置灰与恢复是一次状态切换,底色与字色淡着换,不硬切 */
46
47
  transition:
47
- background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
48
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
48
49
  color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
49
50
  }
50
51
 
@@ -69,7 +70,7 @@
69
70
  }
70
71
 
71
72
  /* 淡底档:带内距、换成 subtle 底,描边让位给底色但留住 1px 边位(与 outline 几何一致),无影;
72
- 淡底承载面向条目下发 hover 200 → pressed 300(§7.2) */
73
+ 淡底承载面向条目下发 hover 200 → pressed 300 */
73
74
  [data-scope='toolbar'][data-part='root'][data-variant='subtle'] {
74
75
  --xh-_toolbar-root-p: var(--xh-_toolbar-p);
75
76
  --xh-_toolbar-root-border-width: var(--xh-stroke-thin);
@@ -78,7 +79,7 @@
78
79
  --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
79
80
  }
80
81
 
81
- /* 附着式工具面:一张静态内容面,--xh-border-default 描边 + surface 底 + 无影(§5.3 边界只由描边承担)。 */
82
+ /* 附着式工具面:一张静态内容面,--xh-border-default 描边 + surface 底 + 无影(边界只由描边承担)。 */
82
83
  [data-scope='toolbar'][data-part='root'][data-variant='outline'] {
83
84
  --xh-_toolbar-root-p: var(--xh-_toolbar-p);
84
85
  --xh-_toolbar-root-border-width: var(--xh-stroke-thin);
@@ -145,7 +146,7 @@
145
146
 
146
147
  /* 默认条目是一枚无描边工具按钮:盒型、三档几何、悬停 / 按下 / 禁用面与按压缩放由 Action Control 的
147
148
  text 档给(ghost 形态:ghost 根按画布承载 hover 100 → pressed 200,subtle 根与分组由 host 槽下发
148
- 200 → 300,§7.2);这里只把使用者槽映射到桥接槽(-gap / -h / -px / -radius / -bg / -bg-hover /
149
+ 200 → 300);这里只把使用者槽映射到桥接槽(-gap / -h / -px / -radius / -bg / -bg-hover /
149
150
  -bg-active / -bg-disabled / -fg / -font-size 保留为第一参数)。作者仍可用类名或内联样式完整覆盖。 */
150
151
  [data-scope='toolbar'][data-part='item'] {
151
152
  --xh-action-gap: var(--xh-toolbar-item-gap, var(--xh-control-gap-sm));
@@ -165,7 +166,7 @@
165
166
  touch-action: manipulation;
166
167
  }
167
168
 
168
- /* 无滑块开关的按下态(§7.3):品牌淡底 + 淡底前景,hover / 按下沿 12% → 20% → 28% 三档走;
169
+ /* 无滑块开关的按下态:品牌淡底 + 淡底前景,hover / 按下沿 12% → 20% → 28% 三档走;
169
170
  三态都经桥接槽交给家族画,禁用面仍由家族按 data-disabled 给 */
170
171
  [data-scope='toolbar'][data-part='item'][aria-pressed='true'] {
171
172
  --xh-action-bg-rest: var(--xh-toolbar-item-bg-pressed, var(--xh-bg-brand-subtle));
@@ -181,12 +182,16 @@
181
182
  }
182
183
 
183
184
  /* 组内分段使用同一块中性操作面(淡底承载:hover 200 → pressed 300 由 host 槽下发);
184
- 中间段保持直角,只给整组两端补回控件圆角。按下态 / 禁用面与散落条目同一套规则 */
185
+ 中间段保持直角,只给整组两端补回控件圆角。按下态 / 禁用面与散落条目同一套规则。
186
+ 分段零间距直角相接,按下只换面不缩放:缩放任一段都会把两侧接缝撕开 */
185
187
  [data-scope='toolbar'][data-part='group'] > [data-scope='toolbar'][data-part='item'] {
186
188
  --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
187
189
  --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
188
190
  --xh-action-radius: 0;
191
+ --xh-action-scale-pressed: none;
189
192
  --xh-action-bg-disabled: var(--xh-toolbar-item-bg-disabled, var(--xh-bg-subtle));
193
+ /* 组末端补回的控件圆角:尾部几段收进「更多」菜单后,由留下的最后一段接过去 */
194
+ --xh-_toolbar-segment-end-radius: var(--xh-toolbar-item-radius, var(--xh-shape-control));
190
195
 
191
196
  position: relative;
192
197
  }
@@ -257,6 +262,80 @@
257
262
  margin-block-start: calc(-1 * var(--xh-toolbar-separator-thickness, var(--xh-stroke-thin)));
258
263
  }
259
264
 
265
+ /* —— 收纳 —— */
266
+ /* 放了「更多」钮就不折行:放不下的条目按次序收进它弹出的菜单。条目与分组不压缩——压缩了,
267
+ 量到的就不是自然长度;root 在 flex 父容器里可以被压到比内容窄,可用长度由外面给 */
268
+ [data-scope='toolbar'][data-part='root']:has(> [data-scope='toolbar'][data-part='overflow-trigger']) {
269
+ flex-wrap: nowrap;
270
+ min-inline-size: 0;
271
+ min-block-size: 0;
272
+ }
273
+
274
+ [data-scope='toolbar'][data-part='root']:has(> [data-scope='toolbar'][data-part='overflow-trigger'])
275
+ > :is([data-scope='toolbar'][data-part='item'], [data-scope='toolbar'][data-part='group']) {
276
+ flex-shrink: 0;
277
+ }
278
+
279
+ /* 收起的条目之前的分隔线与整组收空的分组一并让开:它们分隔的那一侧已经没有露着的条目,
280
+ 留着会在「更多」钮前多出一道线、多出一截间距 */
281
+ [data-scope='toolbar'][data-part='root']:has(> [data-scope='toolbar'][data-part='overflow-trigger']:not([hidden]))
282
+ > [data-scope='toolbar'][data-part='separator']:not(
283
+ :has(
284
+ ~ [data-scope='toolbar'][data-part='item']:not([hidden]),
285
+ ~ [data-scope='toolbar'][data-part='group'] > [data-scope='toolbar'][data-part='item']:not([hidden])
286
+ )
287
+ ),
288
+ [data-scope='toolbar'][data-part='root']:has(> [data-scope='toolbar'][data-part='overflow-trigger']:not([hidden]))
289
+ > [data-scope='toolbar'][data-part='group']:not(:has(> [data-scope='toolbar'][data-part='item']:not([hidden]))),
290
+ [data-scope='toolbar'][data-part='root']:has(> [data-scope='toolbar'][data-part='overflow-trigger']:not([hidden]))
291
+ > [data-scope='toolbar'][data-part='group']
292
+ > [data-scope='toolbar'][data-part='separator']:not(:has(~ [data-scope='toolbar'][data-part='item']:not([hidden]))) {
293
+ display: none;
294
+ }
295
+
296
+ /* 组的尾部几段收进菜单后,留下的最后一段补回末端圆角 */
297
+ [data-scope='toolbar'][data-part='group'][data-orientation='horizontal']
298
+ > [data-scope='toolbar'][data-part='item']:not([hidden]):not(:has(~ [data-scope='toolbar'][data-part='item']:not([hidden]))) {
299
+ border-start-end-radius: var(--xh-_toolbar-segment-end-radius);
300
+ border-end-end-radius: var(--xh-_toolbar-segment-end-radius);
301
+ }
302
+
303
+ [data-scope='toolbar'][data-part='group'][data-orientation='vertical']
304
+ > [data-scope='toolbar'][data-part='item']:not([hidden]):not(:has(~ [data-scope='toolbar'][data-part='item']:not([hidden]))) {
305
+ border-end-start-radius: var(--xh-_toolbar-segment-end-radius);
306
+ border-end-end-radius: var(--xh-_toolbar-segment-end-radius);
307
+ }
308
+
309
+ /* 「更多」钮:行尾一枚单图标钮,接 Action Control icon 档 ghost 面,与条目同档(连接层投影 profile /
310
+ variant / size)。盒取条目同高的正方形,四态面、0.97 按压、焦点环与粗指针 44px 命中区由家族配方给;
311
+ 承载面的阶梯随根的 variant 经 host 槽下发(ghost 根白底 100 → 200,subtle 根淡底 200 → 300) */
312
+ [data-scope='toolbar'][data-part='overflow-trigger'] {
313
+ touch-action: manipulation;
314
+ }
315
+
316
+ /* 菜单开着:与悬停同档的中性面,不用品牌色、不另画环;收起的是哪几条由菜单本身说明 */
317
+ [data-scope='toolbar'][data-part='overflow-trigger'][data-state='open'] {
318
+ --xh-action-bg-rest: var(--xh-_action-variant-bg-hover);
319
+ --xh-action-bg-focus-visible: var(--xh-_action-variant-bg-hover);
320
+ }
321
+
322
+ /* 没写内容就由皮肤画兜底字形:横排三点。作者塞了自己的图标这条即不命中;
323
+ 字形与条目里的图标同一把尺(根按尺寸档下发的 --xh-icon-size) */
324
+ [data-scope='toolbar'][data-part='overflow-trigger']:empty::before {
325
+ content: '';
326
+ display: inline-block;
327
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
328
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
329
+ background-color: currentColor;
330
+ -webkit-mask: var(--xh-glyph-mark-ellipsis) center / contain no-repeat;
331
+ mask: var(--xh-glyph-mark-ellipsis) center / contain no-repeat;
332
+ }
333
+
334
+ /* 全部放得下时连接层给的是 hidden 属性;家族那条 display 会把 UA 规则盖掉 */
335
+ [data-scope='toolbar'][data-part='overflow-trigger'][hidden] {
336
+ display: none;
337
+ }
338
+
260
339
  @media (forced-colors: active) {
261
340
  /* 分段之间那条线画的是一块纯底色,这一档里底色被统一换成 Canvas,线整条消失,
262
341
  几段控件就连成了一长串。换成前景色画回来 */
@@ -264,4 +343,23 @@
264
343
  background: CanvasText;
265
344
  }
266
345
  }
346
+
347
+ @media (forced-colors: active) {
348
+ /* 兜底字形是 mask 挖出来的一块底色,这一档里底色被系统换成 Canvas,字形跟着消失。
349
+ 字形退出强制换色、直接写系统色(不能取 currentColor:退出强制换色的伪元素读到的是被系统换掉之前的作者色):
350
+ 按钮面上取 ButtonText,悬停与按下时家族把按钮涂成 Highlight、字形换 HighlightText;
351
+ 禁用取 GrayText */
352
+ [data-scope='toolbar'][data-part='overflow-trigger']:empty::before {
353
+ forced-color-adjust: none;
354
+ background-color: ButtonText;
355
+ }
356
+
357
+ [data-scope='toolbar'][data-part='overflow-trigger']:not([data-disabled]):not([data-loading]):is(:hover, :active, [data-pressed]):empty::before {
358
+ background-color: HighlightText;
359
+ }
360
+
361
+ [data-scope='toolbar'][data-part='overflow-trigger'][data-disabled]:empty::before {
362
+ background-color: GrayText;
363
+ }
364
+ }
267
365
  }
package/css/tooltip.css CHANGED
@@ -75,10 +75,10 @@
75
75
  --xh-_tooltip-py: var(--xh-space-1);
76
76
  --xh-_tooltip-px: var(--xh-space-2);
77
77
  --xh-_tooltip-font-size: var(--xh-control-caption-md);
78
- /* Tooltip 保留反白身份(真源 §8.4 登记的反白 compact frosted):短提示要与可交互的普通主题浮层一眼分开。
78
+ /* Tooltip 保留反白身份(登记的反白 compact frosted):短提示要与可交互的普通主题浮层一眼分开。
79
79
  94% 是六种 tone 在纯黑/纯白最坏底色上仍托住 4.5:1 正文的首个安全档。
80
80
  边不取 --xh-material-frosted-border:那是深色 14% 的透明边,压在反白深底上看不见,
81
- §8.1 要求的 1px 可见边界由 on 色 20% 拼色承担;§8.1 禁玻璃高光,顶光缺省不画 */
81
+ 浮层要的 1px 可见边界由 on 色 20% 拼色承担;浮层不用玻璃高光,顶光缺省不画 */
82
82
  --xh-_tooltip-solid: var(--xh-_tone, var(--xh-fg-default));
83
83
  --xh-_tooltip-on: var(--xh-_tone-on, var(--xh-bg-surface));
84
84
  --xh-_tooltip-border: color-mix(in oklab, var(--xh-_tooltip-on) 20%, transparent);
@@ -106,7 +106,7 @@
106
106
  text-wrap: pretty;
107
107
  --xh-_tooltip-elevation-shadow: var(--xh-tooltip-shadow, var(--xh-material-frosted-compact-shadow));
108
108
 
109
- /* 顶光槽缺省透明(§8.1 不用顶部高光),使用者要加自行灌色 */
109
+ /* 顶光槽缺省透明(不用顶部高光),使用者要加自行灌色 */
110
110
  box-shadow:
111
111
  inset 0 var(--xh-stroke-thin) 0 var(--xh-tooltip-highlight, transparent),
112
112
  var(--xh-_tooltip-elevation-shadow);
@@ -114,6 +114,18 @@
114
114
  backdrop-filter: var(--xh-tooltip-backdrop, var(--xh-material-frosted-compact-backdrop));
115
115
  }
116
116
 
117
+ /* 跟随鼠标的提示压在指针旁边、随指针挪:它接了指针就会挡住 trigger 上的移动,指针一滑进去便算离开了 trigger。
118
+ 这一档浮层本体同样让指针穿过去,停留细看交给 trigger 本身 */
119
+ [data-scope='tooltip'][data-part='positioner'][data-follow-cursor] [data-scope='tooltip'][data-part='content'] {
120
+ pointer-events: none;
121
+ }
122
+
123
+ /* 反白面是一块彩色面(连接层打 data-xh-ink-surface):面内的作者内容按这块底取墨色。
124
+ 底色取自被墨色域改写的令牌,所以域只落在面内的子元素上,这里的取值仍按外层主题解析 */
125
+ [data-scope='tooltip'][data-part='content'][data-xh-ink-surface] {
126
+ --xh-ink-surface: var(--xh-tooltip-bg, var(--xh-_tooltip-solid));
127
+ }
128
+
117
129
  /* 光学层单独承载 tint 与透明度;backdrop-filter 只采样元素背后,不处理正文。 */
118
130
  [data-scope='tooltip'][data-part='content']::before {
119
131
  content: '';
@@ -126,11 +138,10 @@
126
138
  pointer-events: none;
127
139
  }
128
140
 
129
- /* 入场走 enter 档(§9.5:锚定列表族的 tooltip 入场 --xh-motion-duration-enter),退场仍是 exit */
130
- [data-scope='tooltip'][data-part='content'][data-state='open'] {
141
+ /* 入场走 enter 档(锚定列表族的 tooltip 入场 --xh-motion-duration-enter),退场仍是 exit。
142
+ 接替上一个提示打开的(data-instant)直接呈现:横扫一排钮时提示一个个跟上,不再一个个滑入 */
143
+ [data-scope='tooltip'][data-part='content'][data-state='open']:not([data-instant]) {
131
144
  animation: xh-overlay-slide-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong);
132
- /* 只在开着的这一档挂:合成层随 data-state 一起收走,收起后不再占着 */
133
- will-change: opacity, translate;
134
145
  }
135
146
 
136
147
  /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,