@xihan-ui/styles 1.0.0 → 2.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 (171) hide show
  1. package/CHANGELOG.md +5146 -6
  2. package/README.md +22 -2
  3. package/component-tokens.d.ts +4212 -0
  4. package/component-tokens.js +2 -0
  5. package/components.tokens.json +80116 -0
  6. package/css/accordion.css +131 -75
  7. package/css/affix.css +16 -1
  8. package/css/alert.css +114 -67
  9. package/css/anchor.css +99 -27
  10. package/css/approval.css +461 -0
  11. package/css/avatar-group.css +14 -6
  12. package/css/avatar.css +33 -9
  13. package/css/back-top.css +103 -48
  14. package/css/badge.css +42 -14
  15. package/css/bar-code.css +62 -0
  16. package/css/breadcrumb.css +40 -21
  17. package/css/button-group.css +146 -24
  18. package/css/button.css +116 -99
  19. package/css/calendar-picker.css +448 -0
  20. package/css/calendar-range-picker.css +517 -0
  21. package/css/card.css +54 -77
  22. package/css/carousel.css +412 -68
  23. package/css/cascader.css +429 -246
  24. package/css/checkbox-group.css +225 -77
  25. package/css/checkbox.css +174 -37
  26. package/css/clipboard.css +266 -47
  27. package/css/code-view.css +279 -0
  28. package/css/collapsible.css +108 -63
  29. package/css/color-field.css +158 -0
  30. package/css/color-picker.css +172 -184
  31. package/css/color-slider.css +274 -0
  32. package/css/color-swatch-picker.css +243 -0
  33. package/css/color-swatch.css +35 -0
  34. package/css/combobox.css +267 -273
  35. package/css/command.css +399 -0
  36. package/css/context-menu.css +183 -108
  37. package/css/date-field.css +94 -121
  38. package/css/date-picker.css +486 -249
  39. package/css/date-range-picker.css +559 -0
  40. package/css/description.css +51 -0
  41. package/css/descriptions.css +133 -87
  42. package/css/dialog.css +247 -68
  43. package/css/diff-view.css +428 -0
  44. package/css/download-trigger.css +155 -46
  45. package/css/drawer.css +194 -111
  46. package/css/editable.css +172 -152
  47. package/css/empty-state.css +80 -11
  48. package/css/field-array.css +190 -0
  49. package/css/field.css +84 -31
  50. package/css/fieldset.css +51 -18
  51. package/css/file-upload.css +134 -36
  52. package/css/flex.css +20 -1
  53. package/css/float-button.css +238 -57
  54. package/css/floating-panel.css +173 -92
  55. package/css/focus.css +46 -0
  56. package/css/forced-colors.css +93 -0
  57. package/css/form.css +254 -77
  58. package/css/gradient-text.css +34 -10
  59. package/css/grid.css +516 -5
  60. package/css/heatmap.css +87 -29
  61. package/css/highlight.css +20 -5
  62. package/css/hover-card.css +97 -47
  63. package/css/icon-wrapper.css +15 -3
  64. package/css/icon.css +74 -8
  65. package/css/image-cropper.css +143 -29
  66. package/css/image-viewer.css +150 -89
  67. package/css/image.css +30 -1
  68. package/css/infinite-scroll.css +51 -1
  69. package/css/input-group.css +277 -0
  70. package/css/json-viewer.css +102 -45
  71. package/css/kbd.css +72 -0
  72. package/css/label.css +78 -0
  73. package/css/layers.css +5 -0
  74. package/css/layout.css +175 -31
  75. package/css/list.css +24 -3
  76. package/css/listbox.css +208 -67
  77. package/css/loading-bar.css +52 -3
  78. package/css/log.css +144 -9
  79. package/css/markdown-stream.css +149 -0
  80. package/css/marquee.css +27 -1
  81. package/css/masonry.css +7 -0
  82. package/css/matrix-code.css +67 -0
  83. package/css/mention.css +234 -152
  84. package/css/menu.css +180 -83
  85. package/css/menubar.css +204 -136
  86. package/css/message-feed.css +197 -0
  87. package/css/navigation-menu.css +144 -90
  88. package/css/notification.css +178 -100
  89. package/css/number-animation.css +7 -0
  90. package/css/number-field.css +120 -277
  91. package/css/overlay-arrow.css +12 -7
  92. package/css/page-header.css +99 -14
  93. package/css/pagination.css +175 -135
  94. package/css/password-input.css +222 -219
  95. package/css/pin-input.css +101 -67
  96. package/css/pointer.css +36 -0
  97. package/css/popconfirm.css +185 -94
  98. package/css/popover.css +121 -77
  99. package/css/progress.css +60 -12
  100. package/css/prompt-input.css +224 -0
  101. package/css/question-flow.css +513 -0
  102. package/css/radio-group.css +147 -30
  103. package/css/rating.css +193 -43
  104. package/css/reasoning.css +336 -0
  105. package/css/reset.css +84 -6
  106. package/css/resizable.css +237 -0
  107. package/css/scroll-area.css +68 -7
  108. package/css/scrollbar.css +47 -13
  109. package/css/segmented.css +94 -29
  110. package/css/select.css +288 -274
  111. package/css/separator.css +101 -1
  112. package/css/side-nav.css +133 -75
  113. package/css/signature-pad.css +74 -54
  114. package/css/skeleton.css +84 -11
  115. package/css/slider.css +132 -39
  116. package/css/sortable.css +198 -0
  117. package/css/spinner.css +126 -12
  118. package/css/splitter.css +29 -8
  119. package/css/statistic.css +55 -0
  120. package/css/steps.css +206 -72
  121. package/css/switch.css +268 -36
  122. package/css/table.css +695 -118
  123. package/css/tabs.css +604 -42
  124. package/css/tag-group.css +219 -0
  125. package/css/tag.css +118 -28
  126. package/css/tags-input.css +156 -274
  127. package/css/text-field.css +101 -249
  128. package/css/time-field.css +100 -128
  129. package/css/time-picker.css +323 -252
  130. package/css/time-range-picker.css +719 -0
  131. package/css/timeline.css +202 -68
  132. package/css/timer.css +56 -52
  133. package/css/timestamp.css +34 -0
  134. package/css/toast.css +373 -144
  135. package/css/toggle-group.css +309 -76
  136. package/css/toggle.css +116 -85
  137. package/css/tone.css +47 -0
  138. package/css/tool-call.css +421 -0
  139. package/css/toolbar.css +181 -33
  140. package/css/tooltip.css +107 -36
  141. package/css/tour.css +183 -152
  142. package/css/transfer.css +351 -138
  143. package/css/tree-select.css +323 -216
  144. package/css/tree.css +294 -62
  145. package/css/truncate.css +65 -0
  146. package/css/typography.css +228 -5
  147. package/css/undefined.css +10 -1
  148. package/css/virtualizer.css +9 -10
  149. package/css/visually-hidden.css +7 -0
  150. package/css/watermark.css +7 -0
  151. package/family/action-control.css +487 -0
  152. package/family/collection-item.css +721 -0
  153. package/family/field-chrome.css +298 -0
  154. package/family/motion.css +166 -0
  155. package/family/swatch.css +59 -0
  156. package/index.css +41705 -126
  157. package/index.unlayered.css +33692 -17339
  158. package/package.json +51 -17
  159. package/css/calendar.css +0 -367
  160. package/css/code-block.css +0 -91
  161. package/css/composer.css +0 -134
  162. package/css/countdown.css +0 -26
  163. package/css/dynamic-input.css +0 -220
  164. package/css/ellipsis.css +0 -52
  165. package/css/hotkeys.css +0 -90
  166. package/css/popselect.css +0 -391
  167. package/css/qr-code.css +0 -55
  168. package/css/result.css +0 -119
  169. package/css/space.css +0 -117
  170. package/css/thread.css +0 -120
  171. package/css/time.css +0 -25
@@ -0,0 +1,421 @@
1
+ /*
2
+ * Copyright (c) 2021-Present XiHanFun and contributors.
3
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
4
+ */
5
+
6
+ /* 定义 tool call 样式。 */
7
+
8
+ /* 共享关键帧由 family/motion.css 提供,本皮肤 @import 它,单独引入仍成立;
9
+ 独立皮肤同时传递引入开关的动作控件配方,full bundle 递归去重。 */
10
+ @import '../family/motion.css';
11
+ @import '../family/action-control.css';
12
+
13
+ @layer xihan.components {
14
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15
+ [data-scope='tool-call'] {
16
+ --xh-tool-call-skin: 1;
17
+ }
18
+
19
+ /* 一张静态内容面:--xh-border-default 描边 + surface 底 + 无影(§5.3 边界只由描边承担);
20
+ 审批位与详情区的内部分隔线走另一支 --xh-tool-call-divider(subtle)。
21
+ 卡片建出来时淡入并向上收一段,一屏若干张的错峰交给外层容器排 */
22
+ [data-scope='tool-call'][data-part='root'] {
23
+ /* 尺寸缺省档:不写 data-size 时的取值。三档都只写这三个私有槽,
24
+ 公开槽留在读处当首选,作者在祖先上设的覆盖才赢得过档位声明 */
25
+ --xh-_tool-call-px: var(--xh-space-3);
26
+ --xh-_tool-call-py: var(--xh-space-2);
27
+ --xh-_tool-call-font-size: var(--xh-control-font-md);
28
+
29
+ /* 影另落一份进私有槽给语气档:它要把影与左侧色条叠成一条 box-shadow,缺省无影写成零影占位 */
30
+ --xh-_tool-call-shadow: var(--xh-tool-call-shadow, 0 0 0 transparent);
31
+
32
+ /* 作者塞进指示符里的图标与皮肤画的兜底字形同一把尺:md 档(§6.5),开关上另按家族档取值 */
33
+ --xh-icon-size: var(--xh-tool-call-icon-size, var(--xh-glyph-size-md));
34
+
35
+ display: block;
36
+ overflow: hidden;
37
+ border: var(--xh-stroke-thin) solid var(--xh-tool-call-border, var(--xh-border-default));
38
+ border-radius: var(--xh-tool-call-radius, var(--xh-shape-surface));
39
+ background: var(--xh-tool-call-bg, var(--xh-bg-surface));
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;
42
+ }
43
+
44
+ /* 上面声明的 display 会盖掉 UA 的 [hidden]{display:none},这里补回 */
45
+ [data-scope='tool-call'][data-part='root'][hidden] {
46
+ display: none;
47
+ }
48
+
49
+ /* —— 形态 —— */
50
+ /* 缺省档即 outline,写在上面那条基础规则里 */
51
+ /* 底色分区:描边让位给底色,嵌在别人的面里时不再多一圈线;
52
+ 淡底承载面向开关下发 hover 200 → pressed 300(§7.2) */
53
+ [data-scope='tool-call'][data-part='root'][data-variant='subtle'] {
54
+ --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
55
+ --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
56
+
57
+ border-color: transparent;
58
+ background: var(--xh-tool-call-bg, var(--xh-bg-subtle));
59
+ }
60
+
61
+ /* 无壳内联:卡中卡时不再自带一张面,跟着外层的底走 */
62
+ [data-scope='tool-call'][data-part='root'][data-variant='ghost'] {
63
+ --xh-_tool-call-shadow: 0 0 0 transparent;
64
+
65
+ overflow: visible;
66
+ border-color: transparent;
67
+ background: none;
68
+ box-shadow: none;
69
+ }
70
+
71
+ /* 无壳档的开关只占文字宽度(盖掉 profile 的铺满一行),自己带圆角,悬停时才浮出一块底 */
72
+ [data-scope='tool-call'][data-part='root'][data-variant='ghost'] [data-scope='tool-call'][data-part='trigger'] {
73
+ --xh-action-radius: var(--xh-tool-call-trigger-radius, var(--xh-shape-control));
74
+
75
+ inline-size: auto;
76
+ }
77
+
78
+ /* 出错态换描边色,与语气轴各管各的:语气是作者定的强调,出错是组件自己的阶段。
79
+ 根上的 data-state 已经被开合占着,阶段落成 data-errored 这一位;八个承载阶段的部件
80
+ 渲出任何一个时那条 :has() 同样命中,两条并列,作者只渲根也照样变色 */
81
+ [data-scope='tool-call'][data-part='root'][data-errored],
82
+ [data-scope='tool-call'][data-part='root']:has([data-scope='tool-call'][data-state='output-error']) {
83
+ border-color: var(--xh-tool-call-border-error, var(--xh-border-invalid));
84
+ }
85
+
86
+ /* 开关铺满一行,盒型、悬停 / 按下 / 禁用面由 Action Control 的 disclosure-trigger 档给(ghost 形态:
87
+ 白底承载 hover 100 → pressed 200,按下只换面不缩放,§9.2);这里只把使用者槽映射到桥接槽:
88
+ 圆角归零贴住卡边,内衬与字号沿用卡片的档位(不取 profile 的 md 档内衬,几何不变),
89
+ 字形按开关自己的档位取 --xh-_action-profile-glyph-size */
90
+ [data-scope='tool-call'][data-part='trigger'] {
91
+ --xh-action-radius: 0;
92
+ --xh-action-gap: var(--xh-tool-call-trigger-gap, var(--xh-space-2));
93
+ --xh-action-padding-inline: var(--xh-tool-call-px, var(--xh-_tool-call-px));
94
+ --xh-action-padding-block: var(--xh-tool-call-py, var(--xh-_tool-call-py));
95
+ --xh-action-font-size: var(--xh-tool-call-font-size, var(--xh-_tool-call-font-size));
96
+ --xh-action-fg-rest: var(--xh-tool-call-trigger-fg, var(--xh-fg-default));
97
+ --xh-action-bg-hover: var(--xh-tool-call-trigger-bg-hover, var(--xh-_action-variant-bg-hover));
98
+ --xh-icon-size: var(--xh-tool-call-icon-size, var(--xh-_action-profile-glyph-size));
99
+
100
+ border-width: 0;
101
+ }
102
+
103
+ [data-scope='tool-call'][data-part='trigger'][hidden] {
104
+ display: none;
105
+ }
106
+
107
+ /* 指示随开合转向,纯装饰 */
108
+ [data-scope='tool-call'][data-part='indicator'] {
109
+ display: inline-flex;
110
+ flex: none;
111
+ align-items: center;
112
+ justify-content: center;
113
+ 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);
116
+ }
117
+
118
+ /* 没写内容就由皮肤画;作者往部件里塞了自己的图形,这条规则即不命中 */
119
+ [data-scope='tool-call'][data-part='indicator']:empty::before {
120
+ content: '';
121
+ display: inline-block;
122
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-md));
123
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-md));
124
+ vertical-align: var(--xh-glyph-baseline-shift);
125
+ background-color: currentColor;
126
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
127
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
128
+ }
129
+
130
+ [data-scope='tool-call'][data-part='indicator'][hidden] {
131
+ display: none;
132
+ }
133
+
134
+ /* 收起时朝向行首、展开时转向下方,与逻辑书写方向一致:
135
+ rtl 下 inline-start 在右侧,箭头因此要反着转 */
136
+ [data-scope='tool-call'][data-part='indicator'][data-state='open'] {
137
+ rotate: 90deg;
138
+ }
139
+
140
+ [dir='rtl'] [data-scope='tool-call'][data-part='indicator'] {
141
+ rotate: 180deg;
142
+ }
143
+
144
+ [dir='rtl'] [data-scope='tool-call'][data-part='indicator'][data-state='open'] {
145
+ rotate: 90deg;
146
+ }
147
+
148
+ /* 工具名占满剩余宽度并单行截断:长名字不该把状态挤出去 */
149
+ [data-scope='tool-call'][data-part='label'] {
150
+ display: block;
151
+ overflow: hidden;
152
+ flex: 1 1 auto;
153
+ font-family: var(--xh-tool-call-label-font, var(--xh-font-family-mono));
154
+ text-overflow: ellipsis;
155
+ white-space: nowrap;
156
+ }
157
+
158
+ [data-scope='tool-call'][data-part='label'][hidden] {
159
+ display: none;
160
+ }
161
+
162
+ /* 有摘要时把剩余宽度让给它:工具名只要放得下自己,摘要才是这一行里最想读到的东西 */
163
+ [data-scope='tool-call'][data-part='trigger']:has([data-part='summary']) [data-part='label'] {
164
+ flex: 0 1 auto;
165
+ }
166
+
167
+ /* 一行参数摘要:单行截断的浅底条,收起时也看得见这次查的是什么 */
168
+ [data-scope='tool-call'][data-part='summary'] {
169
+ display: block;
170
+ overflow: hidden;
171
+ flex: 1 1 auto;
172
+ min-inline-size: 0;
173
+ padding-inline: var(--xh-tool-call-summary-px, var(--xh-space-1_5));
174
+ border-radius: var(--xh-tool-call-summary-radius, var(--xh-shape-control));
175
+ background: var(--xh-tool-call-summary-bg, var(--xh-bg-subtle));
176
+ color: var(--xh-tool-call-summary-fg, var(--xh-fg-muted));
177
+ font-family: var(--xh-tool-call-label-font, var(--xh-font-family-mono));
178
+ font-size: var(--xh-tool-call-summary-font-size, var(--xh-text-caption-size));
179
+ text-overflow: ellipsis;
180
+ white-space: nowrap;
181
+ }
182
+
183
+ [data-scope='tool-call'][data-part='summary'][hidden] {
184
+ display: none;
185
+ }
186
+
187
+ [data-scope='tool-call'][data-part='status'] {
188
+ display: inline-flex;
189
+ flex: none;
190
+ align-items: center;
191
+ color: var(--xh-tool-call-status-fg, var(--xh-fg-muted));
192
+ font-size: var(--xh-tool-call-status-font-size, var(--xh-text-caption-size));
193
+ line-height: var(--xh-leading-none);
194
+ }
195
+
196
+ [data-scope='tool-call'][data-part='status'][hidden] {
197
+ display: none;
198
+ }
199
+
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'] {
204
+ 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));
206
+ border-radius: var(--xh-tool-call-status-radius, var(--xh-shape-pill));
207
+ }
208
+
209
+ /* 各阶段的状态色:与语气轴分开走,语气是作者定的强调 */
210
+ [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)));
213
+ }
214
+
215
+ [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)));
218
+ }
219
+
220
+ [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)));
223
+ }
224
+
225
+ /* 在跑的时候状态文字自己扫一道光:data-loading 此前在皮肤里没有任何表达,
226
+ 参数在传与参数齐了两档在屏幕上一模一样。
227
+ 渐变画在背景上再裁进字形,前景与 WebKit 的字形填充色都要透明才透得出底下那道光 */
228
+ [data-scope='tool-call'][data-part='root'][data-loading] [data-part='status'] {
229
+ background-image: linear-gradient(
230
+ 90deg,
231
+ var(--xh-tool-call-status-shimmer-base, var(--xh-fg-subtle)) 35%,
232
+ var(--xh-tool-call-status-shimmer-sheen, var(--xh-fg-default)) 50%,
233
+ var(--xh-tool-call-status-shimmer-base, var(--xh-fg-subtle)) 65%
234
+ );
235
+ background-size: 200% 100%;
236
+ -webkit-background-clip: text;
237
+ background-clip: text;
238
+ color: transparent;
239
+ -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;
241
+ }
242
+
243
+ /* 减少动效:整道光撤掉换回平色,"在跑"仍由状态文字本身表达——只停动画的话,
244
+ 字形里会留着一段冻住的渐变。两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
245
+ @media (prefers-reduced-motion: reduce) {
246
+ [data-scope='tool-call'][data-part='root'][data-loading] [data-part='status'] {
247
+ background-image: none;
248
+ color: var(--xh-tool-call-status-fg, var(--xh-fg-muted));
249
+ -webkit-text-fill-color: currentColor;
250
+ animation: none;
251
+ }
252
+ }
253
+
254
+ :where([data-motion='reduce']) [data-scope='tool-call'][data-part='root'][data-loading] [data-part='status'] {
255
+ background-image: none;
256
+ color: var(--xh-tool-call-status-fg, var(--xh-fg-muted));
257
+ -webkit-text-fill-color: currentColor;
258
+ animation: none;
259
+ }
260
+
261
+ /* 耗时:等宽数位,秒数跳动时不左右挪 */
262
+ [data-scope='tool-call'][data-part='duration'] {
263
+ display: block;
264
+ flex: none;
265
+ color: var(--xh-tool-call-duration-fg, var(--xh-fg-subtle));
266
+ font-size: var(--xh-tool-call-status-font-size, var(--xh-text-caption-size));
267
+ font-variant-numeric: tabular-nums;
268
+ }
269
+
270
+ [data-scope='tool-call'][data-part='duration'][hidden] {
271
+ display: none;
272
+ }
273
+
274
+ /* 审批闸门常驻在开关与详情之间,不随折叠一起藏起来 */
275
+ [data-scope='tool-call'][data-part='approval'] {
276
+ display: block;
277
+ padding-inline: var(--xh-tool-call-px, var(--xh-_tool-call-px));
278
+ padding-block: var(--xh-tool-call-py, var(--xh-_tool-call-py));
279
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-tool-call-divider, var(--xh-border-subtle));
280
+ }
281
+
282
+ [data-scope='tool-call'][data-part='approval'][hidden] {
283
+ display: none;
284
+ }
285
+
286
+ /* 这里刻意没有 [data-part='content'][hidden] { display: none }:补了退场一帧都播不出来。
287
+ 收起由适配器在退场结束后写内联 display 落成,退场窗口内靠 connect 发的 inert 挡住焦点。
288
+ 详情区按阶段取舍,参数、结果与错误同一时刻只排一格,收起时整格随行高归零 */
289
+ [data-scope='tool-call'][data-part='content'] {
290
+ /* 行高与内缩同帧动的共享关键帧读这两条槽:两端内缩同值 */
291
+ --xh-_disclosure-pt: var(--xh-tool-call-py, var(--xh-_tool-call-py));
292
+ --xh-_disclosure-pb: var(--xh-tool-call-py, var(--xh-_tool-call-py));
293
+
294
+ display: grid;
295
+ grid-template-rows: 1fr;
296
+ /* 块轴照旧裁掉:收起靠行高归零,多出来的那一截不能露在外面。
297
+ 行内一轴改成可横滚,宽过卡片的参数与结果推得回来看,不再被裁掉且取不回 */
298
+ overflow-x: auto;
299
+ overflow-y: clip;
300
+ gap: var(--xh-tool-call-content-gap, var(--xh-space-2));
301
+ padding-inline: var(--xh-tool-call-px, var(--xh-_tool-call-px));
302
+ padding-block: var(--xh-tool-call-py, var(--xh-_tool-call-py));
303
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-tool-call-divider, var(--xh-border-subtle));
304
+ }
305
+
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);
310
+ }
311
+
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;
315
+ }
316
+
317
+ [data-scope='tool-call'][data-part='input'],
318
+ [data-scope='tool-call'][data-part='output'] {
319
+ display: block;
320
+ min-inline-size: 0;
321
+ }
322
+
323
+ [data-scope='tool-call'][data-part='input'][hidden],
324
+ [data-scope='tool-call'][data-part='output'][hidden] {
325
+ display: none;
326
+ }
327
+
328
+ /* 出错时开关的 aria-describedby 指过来;流被中止时这里可能是空的 */
329
+ [data-scope='tool-call'][data-part='error'] {
330
+ display: block;
331
+ color: var(--xh-tool-call-error-fg, var(--xh-fg-danger));
332
+ font-size: var(--xh-tool-call-status-font-size, var(--xh-text-caption-size));
333
+ }
334
+
335
+ [data-scope='tool-call'][data-part='error'][hidden] {
336
+ display: none;
337
+ }
338
+
339
+ /* 尺寸档只改内衬与字号 */
340
+ [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);
343
+ --xh-_tool-call-font-size: var(--xh-control-font-sm);
344
+ }
345
+
346
+ [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);
349
+ --xh-_tool-call-font-size: var(--xh-control-font-md);
350
+ }
351
+
352
+ [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);
355
+ --xh-_tool-call-font-size: var(--xh-control-font-lg);
356
+ }
357
+
358
+ /* 语气只染左侧那一条色条,不夺走阶段色;海拔跟着一起写回来,
359
+ box-shadow 是整条替换的,只写色条会把上面那层投影抹掉 */
360
+ [data-scope='tool-call'][data-part='root'][data-tone] {
361
+ box-shadow:
362
+ 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
+ var(--xh-_tool-call-shadow);
364
+ }
365
+ }
366
+
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;
379
+ }
380
+ }
381
+
382
+ /* 一道比字色亮的窄带从右扫到左。背景图比自身宽一倍,靠移动背景位置扫过去,
383
+ 不动布局也不动 transform */
384
+ @keyframes xh-tool-call-shimmer {
385
+ from {
386
+ background-position: 150% center;
387
+ }
388
+
389
+ to {
390
+ background-position: -50% center;
391
+ }
392
+ }
393
+
394
+ @media print {
395
+ /* 打印:动画会被定格在任意一帧——转了一半的圈、扫到一半的微光。这里换成静止的表达,
396
+ 取值与减弱动效那一档相同。两档各写一块、不并进一条媒体查询列表:减弱动效另有一份
397
+ :where([data-motion='reduce']) 的钩子版本与它成对,打印没有对应的钩子可配,
398
+ 并成一条之后这层配对关系在文本上就断了。 */
399
+ [data-scope='tool-call'][data-part='root'][data-loading] [data-part='status'] {
400
+ background-image: none;
401
+ color: var(--xh-tool-call-status-fg, var(--xh-fg-muted));
402
+ -webkit-text-fill-color: currentColor;
403
+ animation: none;
404
+ }
405
+ }
406
+
407
+ /*
408
+ * 高对比档:扫光那层渐变被丢弃,只剩被裁成透明的字形填充,状态文字整段消失。
409
+ * 把两处填充都还回去,在跑这件事仍由状态文字本身表出。
410
+ */
411
+ @media (forced-colors: active) {
412
+ [data-scope='tool-call'][data-part='root'][data-loading] [data-part='status'] {
413
+ background-image: none;
414
+ -webkit-background-clip: border-box;
415
+ background-clip: border-box;
416
+ color: CanvasText;
417
+ -webkit-text-fill-color: currentColor;
418
+ animation: none;
419
+ }
420
+ }
421
+ }