@xihan-ui/styles 1.0.0-alpha.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 (114) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/LICENSE +21 -0
  3. package/README.md +27 -0
  4. package/css/accordion.css +108 -0
  5. package/css/affix.css +27 -0
  6. package/css/alert.css +108 -0
  7. package/css/anchor.css +137 -0
  8. package/css/avatar-group.css +82 -0
  9. package/css/avatar.css +55 -0
  10. package/css/back-top.css +61 -0
  11. package/css/badge.css +50 -0
  12. package/css/breadcrumb.css +127 -0
  13. package/css/button-group.css +131 -0
  14. package/css/button.css +98 -0
  15. package/css/calendar.css +219 -0
  16. package/css/card.css +116 -0
  17. package/css/carousel.css +193 -0
  18. package/css/cascader.css +397 -0
  19. package/css/checkbox-group.css +185 -0
  20. package/css/checkbox.css +91 -0
  21. package/css/clipboard.css +133 -0
  22. package/css/code-block.css +81 -0
  23. package/css/collapsible.css +63 -0
  24. package/css/color-picker.css +424 -0
  25. package/css/combobox.css +433 -0
  26. package/css/composer.css +127 -0
  27. package/css/context-menu.css +263 -0
  28. package/css/countdown.css +21 -0
  29. package/css/date-field.css +200 -0
  30. package/css/date-picker.css +231 -0
  31. package/css/descriptions.css +200 -0
  32. package/css/dialog.css +127 -0
  33. package/css/drawer.css +372 -0
  34. package/css/dynamic-input.css +157 -0
  35. package/css/editable.css +249 -0
  36. package/css/ellipsis.css +41 -0
  37. package/css/empty-state.css +78 -0
  38. package/css/field.css +65 -0
  39. package/css/file-upload.css +298 -0
  40. package/css/flex.css +95 -0
  41. package/css/float-button.css +121 -0
  42. package/css/form.css +185 -0
  43. package/css/gradient-text.css +62 -0
  44. package/css/grid.css +428 -0
  45. package/css/highlight.css +21 -0
  46. package/css/hover-card.css +146 -0
  47. package/css/icon-wrapper.css +64 -0
  48. package/css/icon.css +54 -0
  49. package/css/image.css +45 -0
  50. package/css/infinite-scroll.css +22 -0
  51. package/css/layers.css +2 -0
  52. package/css/layout.css +169 -0
  53. package/css/list.css +117 -0
  54. package/css/listbox.css +174 -0
  55. package/css/loading-bar.css +66 -0
  56. package/css/log.css +66 -0
  57. package/css/marquee.css +182 -0
  58. package/css/mention.css +222 -0
  59. package/css/menu.css +144 -0
  60. package/css/menubar.css +271 -0
  61. package/css/motion.css +58 -0
  62. package/css/navigation-menu.css +270 -0
  63. package/css/number-animation.css +32 -0
  64. package/css/number-field.css +219 -0
  65. package/css/page-header.css +85 -0
  66. package/css/pagination.css +148 -0
  67. package/css/pin-input.css +157 -0
  68. package/css/popconfirm.css +150 -0
  69. package/css/popover.css +150 -0
  70. package/css/popselect.css +207 -0
  71. package/css/progress.css +37 -0
  72. package/css/qr-code.css +50 -0
  73. package/css/radio-group.css +101 -0
  74. package/css/rating.css +141 -0
  75. package/css/reset.css +22 -0
  76. package/css/result.css +104 -0
  77. package/css/scroll-area.css +176 -0
  78. package/css/select.css +264 -0
  79. package/css/separator.css +17 -0
  80. package/css/skeleton.css +78 -0
  81. package/css/slider.css +197 -0
  82. package/css/spinner.css +74 -0
  83. package/css/splitter.css +127 -0
  84. package/css/statistic.css +67 -0
  85. package/css/steps.css +252 -0
  86. package/css/switch.css +61 -0
  87. package/css/table.css +404 -0
  88. package/css/tabs.css +157 -0
  89. package/css/tags-input.css +360 -0
  90. package/css/text-field.css +195 -0
  91. package/css/thread.css +107 -0
  92. package/css/time-field.css +200 -0
  93. package/css/time-picker.css +347 -0
  94. package/css/time.css +20 -0
  95. package/css/timeline.css +284 -0
  96. package/css/toast.css +195 -0
  97. package/css/toaster.css +69 -0
  98. package/css/toggle-group.css +160 -0
  99. package/css/toggle.css +103 -0
  100. package/css/tone.css +85 -0
  101. package/css/toolbar.css +114 -0
  102. package/css/tooltip.css +109 -0
  103. package/css/tour.css +305 -0
  104. package/css/transfer.css +318 -0
  105. package/css/tree-select.css +441 -0
  106. package/css/tree.css +204 -0
  107. package/css/typography.css +151 -0
  108. package/css/undefined.css +38 -0
  109. package/css/virtualizer.css +104 -0
  110. package/css/visually-hidden.css +13 -0
  111. package/css/watermark.css +48 -0
  112. package/index.css +113 -0
  113. package/index.unlayered.css +16164 -0
  114. package/package.json +163 -0
@@ -0,0 +1,433 @@
1
+ @layer xihan.components {
2
+ [data-scope='combobox'][data-part='root'] {
3
+ /* 尺寸档只换这五个私有槽,输入行、标题与候选都从 root 继承它们,
4
+ 换档不必给每个部件各写一条选择器。浮层在 positioner 里、也是 root 的后代,一并继承 */
5
+ --xh-_combobox-h: var(--xh-control-h-md);
6
+ --xh-_combobox-px: var(--xh-control-px-md);
7
+ --xh-_combobox-gap: var(--xh-control-gap-md);
8
+ --xh-_combobox-font-size: var(--xh-text-body-size);
9
+ --xh-_combobox-label-font-size: var(--xh-text-label-size);
10
+
11
+ /* 形态档只换这三个槽:缺省即 outline(描边 + 画布底) */
12
+ --xh-_combobox-control-bg: var(--xh-bg-canvas);
13
+ --xh-_combobox-control-border: var(--xh-border-default);
14
+ --xh-_combobox-control-border-hover: var(--xh-border-strong);
15
+
16
+ /* 强调色随语气走,只落在聚焦与选中上,正文文字色不动。
17
+ 没写 data-tone 时 --xh-_tone 没被声明,三处都退回原来的取值 */
18
+ --xh-_combobox-ring: var(--xh-ring-focus);
19
+ --xh-_combobox-accent: var(--xh-_tone, var(--xh-bg-brand));
20
+ --xh-_combobox-item-highlight-bg: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover));
21
+ --xh-_combobox-item-selected-fg: var(--xh-_tone-fg, var(--xh-fg-brand-strong));
22
+
23
+ display: inline-flex;
24
+ flex-direction: column;
25
+ gap: var(--xh-combobox-gap, var(--xh-stack-gap-md));
26
+ }
27
+
28
+ /* 只要声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去 */
29
+ [data-scope='combobox'][data-part='root'][hidden] {
30
+ display: none;
31
+ }
32
+
33
+ /* —— 尺寸 —— */
34
+ /* 缺省档写在上面的基础规则里 */
35
+ [data-scope='combobox'][data-part='root'][data-size='sm'] {
36
+ --xh-_combobox-h: var(--xh-control-h-sm);
37
+ --xh-_combobox-px: var(--xh-control-px-sm);
38
+ --xh-_combobox-gap: var(--xh-control-gap-sm);
39
+ --xh-_combobox-font-size: var(--xh-font-size-sm);
40
+ --xh-_combobox-label-font-size: var(--xh-font-size-sm);
41
+ }
42
+
43
+ [data-scope='combobox'][data-part='root'][data-size='lg'] {
44
+ --xh-_combobox-h: var(--xh-control-h-lg);
45
+ --xh-_combobox-px: var(--xh-control-px-lg);
46
+ --xh-_combobox-gap: var(--xh-control-gap-lg);
47
+ --xh-_combobox-font-size: var(--xh-font-size-lg);
48
+ --xh-_combobox-label-font-size: var(--xh-font-size-lg);
49
+ }
50
+
51
+ /* —— 形态 —— */
52
+ /* 输入类不做 solid:实心底压着可编辑的文字,读起来像块不可点的色板。
53
+ 形态只决定描边与底色怎么用,用哪族颜色由 data-tone 决定 */
54
+ [data-scope='combobox'][data-part='root'][data-variant='outline'] {
55
+ --xh-_combobox-control-bg: var(--xh-bg-canvas);
56
+ --xh-_combobox-control-border: var(--xh-border-default);
57
+ --xh-_combobox-control-border-hover: var(--xh-border-strong);
58
+ }
59
+
60
+ /* 填充式:底色顶替描边,悬停时才浮出一道淡边 */
61
+ [data-scope='combobox'][data-part='root'][data-variant='subtle'] {
62
+ --xh-_combobox-control-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
63
+ --xh-_combobox-control-border: transparent;
64
+ --xh-_combobox-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
65
+ }
66
+
67
+ [data-scope='combobox'][data-part='root'][data-variant='ghost'] {
68
+ --xh-_combobox-control-bg: transparent;
69
+ --xh-_combobox-control-border: transparent;
70
+ --xh-_combobox-control-border-hover: var(--xh-_tone-border, var(--xh-border-default));
71
+ }
72
+
73
+ [data-scope='combobox'][data-part='label'] {
74
+ color: var(--xh-combobox-label-fg, var(--xh-fg-muted));
75
+ font-size: var(--xh-combobox-label-font-size, var(--xh-_combobox-label-font-size));
76
+ font-weight: var(--xh-combobox-label-font-weight, var(--xh-text-label-weight));
77
+ line-height: var(--xh-leading-none);
78
+ }
79
+
80
+ [data-scope='combobox'][data-part='label'][data-disabled] {
81
+ color: var(--xh-fg-subtle);
82
+ }
83
+
84
+ /* 画成一个框的是 control 而不是 input:输入框、展开按钮、清空按钮三者要看起来是一体的,
85
+ 边框长在里面任何一个身上都会把另外两个割在框外 */
86
+ [data-scope='combobox'][data-part='control'] {
87
+ display: inline-flex;
88
+ align-items: center;
89
+ gap: var(--xh-combobox-control-gap, var(--xh-_combobox-gap));
90
+ min-inline-size: var(--xh-combobox-control-min-w, var(--xh-overlay-min-w));
91
+ block-size: var(--xh-combobox-control-h, var(--xh-_combobox-h));
92
+ padding-inline: var(--xh-combobox-control-px, var(--xh-_combobox-px));
93
+ border: var(--xh-stroke-thin) solid var(--xh-combobox-control-border, var(--xh-_combobox-control-border));
94
+ border-radius: var(--xh-combobox-control-radius, var(--xh-shape-control));
95
+ background: var(--xh-combobox-control-bg, var(--xh-_combobox-control-bg));
96
+ color: var(--xh-combobox-control-fg, var(--xh-fg-default));
97
+ transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
98
+ }
99
+
100
+ [data-scope='combobox'][data-part='control'][hidden] {
101
+ display: none;
102
+ }
103
+
104
+ /* hover 只在中性态换描边:invalid 正拿边框颜色说事,被 hover 盖掉那条信息就没了 */
105
+ [data-scope='combobox'][data-part='control']:hover:not([data-disabled], [data-invalid]) {
106
+ border-color: var(--xh-combobox-control-border-hover, var(--xh-_combobox-control-border-hover));
107
+ }
108
+
109
+ /* 焦点环画在 control 上而不是 input 上:视觉上的「框」是 control,
110
+ 环若长在里面那个透明的 input 身上,就会缩在文字区里、与框错开一圈。
111
+ input 是这里唯一可聚焦的常规节点,:focus-within 与它的 :focus-visible 等价 */
112
+ [data-scope='combobox'][data-part='control']:focus-within {
113
+ border-color: var(--xh-combobox-control-border-focus, var(--xh-_combobox-ring));
114
+ outline: var(--xh-ring-width) solid var(--xh-_combobox-ring);
115
+ outline-offset: var(--xh-ring-offset);
116
+ }
117
+
118
+ [data-scope='combobox'][data-part='control'][data-invalid] {
119
+ border-color: var(--xh-combobox-control-border-invalid, var(--xh-color-danger-500));
120
+ }
121
+
122
+ /* 只读仍可聚焦、可复制,所以不置灰,只把底色压下去表示"改不动" */
123
+ [data-scope='combobox'][data-part='control'][data-readonly] {
124
+ background: var(--xh-combobox-control-bg-readonly, var(--xh-bg-subtle));
125
+ }
126
+
127
+ [data-scope='combobox'][data-part='control'][data-disabled] {
128
+ background: var(--xh-combobox-control-bg-disabled, var(--xh-bg-subtle));
129
+ color: var(--xh-fg-disabled);
130
+ cursor: not-allowed;
131
+ }
132
+
133
+ /* input 是单体表单控件,禁用走原生 disabled(候选那边一律 aria-disabled)。
134
+ 它自己不画框也不画环,两者都归 control */
135
+ [data-scope='combobox'][data-part='input'] {
136
+ flex: 1;
137
+ min-inline-size: 0;
138
+ block-size: 100%;
139
+ padding: 0;
140
+ border: 0;
141
+ background: transparent;
142
+ color: inherit;
143
+ /* 表单控件不继承页面字体,只给字号会让输入框用 UA 默认字族,与周围文本对不上 */
144
+ font-family: inherit;
145
+ font-size: var(--xh-combobox-input-font-size, var(--xh-_combobox-font-size));
146
+ line-height: var(--xh-leading-normal);
147
+ }
148
+
149
+ [data-scope='combobox'][data-part='input'][hidden] {
150
+ display: none;
151
+ }
152
+
153
+ /* 多行宿主:输入行不再是固定一行高,改由 textarea 自己的行数撑开。
154
+ 两个按钮跟着贴到顶上对齐首行,不然它们会浮在整块文字的正中间 */
155
+ [data-scope='combobox'][data-part='control']:has([data-part='input'][data-multiline]) {
156
+ align-items: start;
157
+ block-size: auto;
158
+ padding-block: var(--xh-field-py);
159
+ }
160
+
161
+ [data-scope='combobox'][data-part='input'][data-multiline] {
162
+ block-size: auto;
163
+ /* 只许纵向拉伸:横向拉宽会把浮层与输入行的对齐拽歪 */
164
+ resize: vertical;
165
+ }
166
+
167
+ [data-scope='combobox'][data-part='input']::placeholder {
168
+ color: var(--xh-combobox-placeholder-fg, var(--xh-fg-subtle));
169
+ }
170
+
171
+ /* 焦点环已由 control 的 :focus-within 画好,这里再画一圈会套成两层 */
172
+ [data-scope='combobox'][data-part='input']:focus-visible {
173
+ outline: none;
174
+ }
175
+
176
+ [data-scope='combobox'][data-part='input']:disabled {
177
+ color: var(--xh-fg-disabled);
178
+ cursor: not-allowed;
179
+ }
180
+
181
+ /* 两个按钮同一副长相:贴在框内右侧的小方钮,不占宽度也不撑高 control */
182
+ [data-scope='combobox'][data-part='trigger'],
183
+ [data-scope='combobox'][data-part='clear-trigger'] {
184
+ display: inline-flex;
185
+ flex: none;
186
+ align-items: center;
187
+ justify-content: center;
188
+ inline-size: var(--xh-combobox-action-size, var(--xh-control-action-size));
189
+ block-size: var(--xh-combobox-action-size, var(--xh-control-action-size));
190
+ padding: 0;
191
+ border: 0;
192
+ border-radius: var(--xh-combobox-action-radius, var(--xh-shape-control));
193
+ background: var(--xh-combobox-action-bg, transparent);
194
+ color: var(--xh-combobox-action-fg, var(--xh-fg-muted));
195
+ font-family: inherit;
196
+ font-size: var(--xh-combobox-action-font-size, var(--xh-font-size-sm));
197
+ line-height: var(--xh-leading-none);
198
+ cursor: pointer;
199
+ user-select: none;
200
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
201
+ }
202
+
203
+ [data-scope='combobox'][data-part='trigger'][hidden],
204
+ [data-scope='combobox'][data-part='clear-trigger'][hidden] {
205
+ display: none;
206
+ }
207
+
208
+ /* 展开时箭头翻个面,指向与列表的去向一致;transition 要重写全份,只补一条会覆盖掉上面那条 */
209
+ [data-scope='combobox'][data-part='trigger'] {
210
+ transition:
211
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
212
+ rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
213
+ }
214
+
215
+ /* 没写内容就由皮肤画箭头;作者往部件里塞了自己的图形,这条规则即不命中 */
216
+ [data-scope='combobox'][data-part='trigger']:empty::before {
217
+ content: '▾';
218
+ }
219
+
220
+ /* 同上:没写内容就由皮肤画叉 */
221
+ [data-scope='combobox'][data-part='clear-trigger']:empty::before {
222
+ content: '✕';
223
+ }
224
+
225
+ [data-scope='combobox'][data-part='trigger'][data-state='open'] {
226
+ rotate: 180deg;
227
+ }
228
+
229
+ [data-scope='combobox'][data-part='trigger']:hover:not(:disabled),
230
+ [data-scope='combobox'][data-part='clear-trigger']:hover:not(:disabled) {
231
+ background: var(--xh-combobox-action-bg-hover, var(--xh-bg-subtle-hover));
232
+ color: var(--xh-combobox-action-fg-hover, var(--xh-fg-default));
233
+ }
234
+
235
+ [data-scope='combobox'][data-part='trigger']:active:not(:disabled),
236
+ [data-scope='combobox'][data-part='clear-trigger']:active:not(:disabled) {
237
+ background: var(--xh-combobox-action-bg-active, var(--xh-bg-subtle-active));
238
+ }
239
+
240
+ /* 两个按钮都退出了 Tab 序列(tabindex=-1),正常操作走不到这里;
241
+ 留着是给程序化聚焦兜底,落焦时得看得见 */
242
+ [data-scope='combobox'][data-part='trigger']:focus-visible,
243
+ [data-scope='combobox'][data-part='clear-trigger']:focus-visible {
244
+ outline: var(--xh-ring-width) solid var(--xh-_combobox-ring);
245
+ outline-offset: var(--xh-ring-offset);
246
+ }
247
+
248
+ [data-scope='combobox'][data-part='trigger']:disabled,
249
+ [data-scope='combobox'][data-part='clear-trigger']:disabled {
250
+ background: var(--xh-combobox-action-bg, transparent);
251
+ color: var(--xh-fg-disabled);
252
+ cursor: not-allowed;
253
+ }
254
+
255
+ /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
256
+ [data-scope='combobox'][data-part='positioner'] {
257
+ position: fixed;
258
+ z-index: var(--xh-layer-popover);
259
+ /* 空壳不吃指针,交互只发生在 content 与 empty 上 */
260
+ pointer-events: none;
261
+ }
262
+
263
+ /* 锚点被滚出可视区:整个浮层随之收起 */
264
+ [data-scope='combobox'][data-part='positioner'][data-hidden] {
265
+ visibility: hidden;
266
+ }
267
+
268
+ [data-scope='combobox'][data-part='content'] {
269
+ display: flex;
270
+ flex-direction: column;
271
+ min-inline-size: var(--xh-combobox-content-min-w, var(--xh-overlay-min-w));
272
+ max-inline-size: var(--xh-combobox-content-max-w, 24rem);
273
+ max-block-size: var(--xh-combobox-content-max-h, var(--xh-overlay-max-h));
274
+ padding-block: var(--xh-combobox-content-py, var(--xh-space-1));
275
+ padding-inline: var(--xh-combobox-content-px, var(--xh-space-1));
276
+ border: var(--xh-stroke-thin) solid var(--xh-combobox-content-border, var(--xh-border-default));
277
+ border-radius: var(--xh-combobox-content-radius, var(--xh-shape-surface));
278
+ background: var(--xh-combobox-content-bg, var(--xh-bg-surface));
279
+ color: var(--xh-combobox-content-fg, var(--xh-fg-default));
280
+ box-shadow: var(--xh-combobox-content-shadow, var(--xh-elevation-2));
281
+ overflow-y: auto;
282
+ pointer-events: auto;
283
+ }
284
+
285
+ /* display 会盖掉 hidden 属性的 UA 规则,收起态显式让位 */
286
+ [data-scope='combobox'][data-part='content'][hidden] {
287
+ display: none;
288
+ }
289
+
290
+ /* 列表从不承载焦点(焦点恒在输入框,高亮走 aria-activedescendant),
291
+ 可滚动容器在某些浏览器里会被自动塞进 Tab 序列,落焦时不画环 */
292
+ [data-scope='combobox'][data-part='content']:focus-visible {
293
+ outline: none;
294
+ }
295
+
296
+ [data-scope='combobox'][data-part='content'][data-state='open'] {
297
+ animation: xh-fade-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
298
+ }
299
+
300
+ [data-scope='combobox'][data-part='item-group'] {
301
+ display: flex;
302
+ flex-direction: column;
303
+ }
304
+
305
+ [data-scope='combobox'][data-part='item-group'][hidden] {
306
+ display: none;
307
+ }
308
+
309
+ /* 组间留白只加在后继分组上:首组顶上已经有 content 的内边距,再加一层会显得头重 */
310
+ [data-scope='combobox'][data-part='item-group'] + [data-scope='combobox'][data-part='item-group'] {
311
+ margin-block-start: var(--xh-combobox-group-gap, var(--xh-space-2));
312
+ }
313
+
314
+ /* 分组标题不是候选、进不了导航,画成小号次要文字,内缩与候选对齐(同一个 padding-inline) */
315
+ [data-scope='combobox'][data-part='item-group-label'] {
316
+ display: block;
317
+ padding-block: var(--xh-combobox-group-label-py, var(--xh-space-1));
318
+ padding-inline: var(--xh-combobox-group-label-px, var(--xh-control-px-sm));
319
+ color: var(--xh-combobox-group-label-fg, var(--xh-fg-subtle));
320
+ font-size: var(--xh-combobox-group-label-font-size, var(--xh-font-size-xs));
321
+ font-weight: var(--xh-combobox-group-label-font-weight, var(--xh-font-weight-medium));
322
+ line-height: var(--xh-leading-none);
323
+ user-select: none;
324
+ }
325
+
326
+ [data-scope='combobox'][data-part='item-group-label'][hidden] {
327
+ display: none;
328
+ }
329
+
330
+ [data-scope='combobox'][data-part='item'] {
331
+ display: flex;
332
+ align-items: center;
333
+ gap: var(--xh-combobox-item-gap, var(--xh-_combobox-gap));
334
+ padding-block: var(--xh-combobox-item-py, var(--xh-space-1));
335
+ padding-inline: var(--xh-combobox-item-px, var(--xh-control-px-sm));
336
+ border-radius: var(--xh-combobox-item-radius, var(--xh-shape-control));
337
+ color: var(--xh-combobox-item-fg, var(--xh-fg-default));
338
+ font-size: var(--xh-combobox-item-font-size, var(--xh-_combobox-font-size));
339
+ /* 行高留出文字的上下伸展空间,行内那层 overflow:hidden 才不会把字削掉 */
340
+ line-height: var(--xh-combobox-item-leading, var(--xh-leading-normal));
341
+ white-space: nowrap;
342
+ cursor: pointer;
343
+ user-select: none;
344
+ }
345
+
346
+ /* 候选按需收起(作者自己藏掉某几条)时要让位,有 display 就得补这条 */
347
+ [data-scope='combobox'][data-part='item'][hidden] {
348
+ display: none;
349
+ }
350
+
351
+ /* 只认 data-highlighted,不写 :hover:指针划过时连接层已经把高亮搬过来了,
352
+ 两套底色各画各的会出现"鼠标停在 A 上、回车提交的却是 B" */
353
+ [data-scope='combobox'][data-part='item'][data-highlighted]:not([data-disabled]) {
354
+ background: var(--xh-combobox-item-bg-highlight, var(--xh-_combobox-item-highlight-bg));
355
+ }
356
+
357
+ /* 选中只换文字色与字重,配合行尾的 ✓ 标记;底色整条通道留给高亮,
358
+ 两者因此能同时看见 */
359
+ [data-scope='combobox'][data-part='item'][data-state='checked'] {
360
+ color: var(--xh-combobox-item-fg-selected, var(--xh-_combobox-item-selected-fg));
361
+ font-weight: var(--xh-combobox-item-font-weight-selected, var(--xh-font-weight-medium));
362
+ }
363
+
364
+ /* 禁用走 aria-disabled 而非原生 disabled(原生 disabled 不派 click,禁用守卫就走不到),
365
+ 所以只能靠 data-disabled 表达,写 :disabled 永远不命中 */
366
+ [data-scope='combobox'][data-part='item'][data-disabled] {
367
+ color: var(--xh-fg-disabled);
368
+ cursor: not-allowed;
369
+ }
370
+
371
+ [data-scope='combobox'][data-part='item-text'] {
372
+ flex: 1;
373
+ /* 弹性项默认 min-width: auto 不肯收缩到内容以下,省略号因此永不生效 */
374
+ min-inline-size: 0;
375
+ overflow: hidden;
376
+ white-space: nowrap;
377
+ text-overflow: ellipsis;
378
+ }
379
+
380
+ [data-scope='combobox'][data-part='item-text'][hidden] {
381
+ display: none;
382
+ }
383
+
384
+ /* 勾选标记只在选中项上出现;未选中时占位不塌,切换选中不引起行宽抖动 */
385
+ [data-scope='combobox'][data-part='item-indicator'] {
386
+ display: inline-flex;
387
+ flex: none;
388
+ align-items: center;
389
+ justify-content: center;
390
+ inline-size: var(--xh-combobox-item-indicator-size, var(--xh-control-indicator-size));
391
+ color: var(--xh-combobox-item-indicator-fg, var(--xh-_combobox-accent));
392
+ visibility: hidden;
393
+ }
394
+
395
+ [data-scope='combobox'][data-part='item-indicator'][hidden] {
396
+ display: none;
397
+ }
398
+
399
+ /* 同上:没写内容就由皮肤画勾 */
400
+ [data-scope='combobox'][data-part='item-indicator']:empty::before {
401
+ content: '✓';
402
+ }
403
+
404
+ [data-scope='combobox'][data-part='item-indicator'][data-state='checked'] {
405
+ visibility: visible;
406
+ }
407
+
408
+ [data-scope='combobox'][data-part='item-indicator'][data-disabled] {
409
+ color: var(--xh-fg-disabled);
410
+ }
411
+
412
+ /* 空态提示是列表之外的一句状态播报(role=status),不进 role=listbox。
413
+ 它与 content 是兄弟,因此要自带浮层的那身皮,否则会光秃秃地飘在页面上 */
414
+ [data-scope='combobox'][data-part='empty'] {
415
+ display: block;
416
+ padding-block: var(--xh-combobox-empty-py, var(--xh-space-3));
417
+ padding-inline: var(--xh-combobox-empty-px, var(--xh-control-px-md));
418
+ border: var(--xh-stroke-thin) solid var(--xh-combobox-empty-border, var(--xh-border-default));
419
+ border-radius: var(--xh-combobox-empty-radius, var(--xh-shape-surface));
420
+ background: var(--xh-combobox-empty-bg, var(--xh-bg-surface));
421
+ color: var(--xh-combobox-empty-fg, var(--xh-fg-subtle));
422
+ font-size: var(--xh-combobox-empty-font-size, var(--xh-_combobox-font-size));
423
+ line-height: var(--xh-leading-none);
424
+ box-shadow: var(--xh-combobox-empty-shadow, var(--xh-elevation-2));
425
+ text-align: center;
426
+ pointer-events: auto;
427
+ }
428
+
429
+ /* 漏了这条,候选一有结果空态提示就永远撤不下去(上面那条 display 盖掉了 UA 的 [hidden] 规则) */
430
+ [data-scope='combobox'][data-part='empty'][hidden] {
431
+ display: none;
432
+ }
433
+ }
@@ -0,0 +1,127 @@
1
+ @layer xihan.components {
2
+ /* 边框画在 root 上,内部 textarea 无边框;align-items: flex-end 让按钮随输入框长高贴着底边 */
3
+ [data-scope='composer'][data-part='root'] {
4
+ /* 输入与发送按钮共用的控件高度 */
5
+ --xh-_composer-control-h: var(--xh-composer-submit-h, var(--xh-control-h-md));
6
+
7
+ display: flex;
8
+ align-items: flex-end;
9
+ gap: var(--xh-composer-gap, var(--xh-control-gap-md));
10
+ padding: var(--xh-composer-p, var(--xh-space-2));
11
+ border: var(--xh-stroke-thin) solid var(--xh-composer-border, var(--xh-border-default));
12
+ border-radius: var(--xh-composer-radius, var(--xh-shape-surface));
13
+ background: var(--xh-composer-bg, var(--xh-bg-surface));
14
+ }
15
+
16
+ /* 上面声明的 display 会盖掉 UA 的 [hidden]{display:none},这里补回 */
17
+ [data-scope='composer'][data-part='root'][hidden] {
18
+ display: none;
19
+ }
20
+
21
+ /* 焦点环画在整个框上;用 focus-within 使焦点落在发送按钮时同样点亮 */
22
+ [data-scope='composer'][data-part='root']:focus-within {
23
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
24
+ outline-offset: var(--xh-ring-offset);
25
+ }
26
+
27
+ /* 禁用态罩住整框,内部 textarea 与按钮另有原生 disabled 管交互 */
28
+ [data-scope='composer'][data-part='root'][data-disabled] {
29
+ cursor: not-allowed;
30
+ opacity: var(--xh-state-disabled-opacity);
31
+ }
32
+
33
+ /* 无边框透明底,融进 root 的框里;min-inline-size: 0 防止长内容把弹性子项撑出容器 */
34
+ [data-scope='composer'][data-part='input'] {
35
+ flex: 1;
36
+ min-inline-size: 0;
37
+ /* 上下留白把单行文本盒撑到控件高度,文字中线与按钮中线对齐 */
38
+ padding-block: calc((var(--xh-_composer-control-h) - 1lh) / 2);
39
+ padding-inline: 0;
40
+ border: 0;
41
+ background: transparent;
42
+ color: var(--xh-composer-input-fg, var(--xh-fg-default));
43
+ /* 表单控件默认不继承页面字族,显式继承 */
44
+ font-family: inherit;
45
+ font-size: var(--xh-composer-input-font-size, var(--xh-text-body-size));
46
+ line-height: var(--xh-leading-normal);
47
+ /* 高度由 field-sizing 随内容变,不支持的引擎退化为 rows 定下的固定行数;
48
+ 配套禁用 resize,避免拖拽写死的高度盖掉它。 */
49
+ field-sizing: content;
50
+ resize: none;
51
+ }
52
+
53
+ /* 焦点环已画在 root 上,这里去掉自身的环 */
54
+ [data-scope='composer'][data-part='input']:focus-visible {
55
+ outline: none;
56
+ }
57
+
58
+ [data-scope='composer'][data-part='input']::placeholder {
59
+ color: var(--xh-composer-placeholder-fg, var(--xh-fg-subtle));
60
+ }
61
+
62
+ /* textarea 是单体表单控件,禁用走原生 disabled */
63
+ [data-scope='composer'][data-part='input']:disabled {
64
+ color: var(--xh-fg-disabled);
65
+ cursor: not-allowed;
66
+ }
67
+
68
+ /* 私有变量槽位,send 与 stop 两个模式只换这几个配色值 */
69
+ [data-scope='composer'][data-part='submit-trigger'] {
70
+ --xh-_bg: var(--xh-composer-send-bg, var(--xh-bg-brand));
71
+ --xh-_bg-hover: var(--xh-composer-send-bg-hover, var(--xh-bg-brand-hover));
72
+ --xh-_bg-active: var(--xh-composer-send-bg-active, var(--xh-bg-brand-active));
73
+ --xh-_fg: var(--xh-composer-send-fg, var(--xh-fg-on-brand));
74
+
75
+ display: inline-flex;
76
+ /* 按钮不参与弹性伸缩 */
77
+ flex: none;
78
+ align-items: center;
79
+ justify-content: center;
80
+ min-inline-size: var(--xh-_composer-control-h);
81
+ block-size: var(--xh-_composer-control-h);
82
+ padding-inline: var(--xh-composer-submit-px, var(--xh-control-px-md));
83
+ border: 0;
84
+ border-radius: var(--xh-composer-submit-radius, var(--xh-shape-control));
85
+ background: var(--xh-_bg);
86
+ color: var(--xh-_fg);
87
+ font-family: inherit;
88
+ font-size: var(--xh-composer-submit-font-size, var(--xh-text-label-size));
89
+ font-weight: var(--xh-composer-submit-font-weight, var(--xh-text-label-weight));
90
+ line-height: var(--xh-leading-none);
91
+ white-space: nowrap;
92
+ cursor: pointer;
93
+ user-select: none;
94
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
95
+ }
96
+
97
+ [data-scope='composer'][data-part='submit-trigger'][hidden] {
98
+ display: none;
99
+ }
100
+
101
+ [data-scope='composer'][data-part='submit-trigger']:hover:not(:disabled) {
102
+ background: var(--xh-_bg-hover);
103
+ }
104
+
105
+ [data-scope='composer'][data-part='submit-trigger']:active:not(:disabled) {
106
+ background: var(--xh-_bg-active);
107
+ }
108
+
109
+ [data-scope='composer'][data-part='submit-trigger']:focus-visible {
110
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
111
+ outline-offset: var(--xh-ring-offset);
112
+ }
113
+
114
+ /* 停止模式只换配色,从主色降到中性;文案与可访问名由连接层切换 */
115
+ [data-scope='composer'][data-part='submit-trigger'][data-mode='stop'] {
116
+ --xh-_bg: var(--xh-composer-stop-bg, var(--xh-bg-subtle));
117
+ --xh-_bg-hover: var(--xh-composer-stop-bg-hover, var(--xh-bg-subtle-hover));
118
+ --xh-_bg-active: var(--xh-composer-stop-bg-active, var(--xh-bg-subtle-active));
119
+ --xh-_fg: var(--xh-composer-stop-fg, var(--xh-fg-default));
120
+ }
121
+
122
+ /* 禁用走原生 disabled,输入为空时按钮转灰但不收起 */
123
+ [data-scope='composer'][data-part='submit-trigger']:disabled {
124
+ color: var(--xh-fg-disabled);
125
+ cursor: not-allowed;
126
+ }
127
+ }