@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
package/css/flex.css CHANGED
@@ -12,8 +12,15 @@
12
12
  }
13
13
 
14
14
  [data-scope='flex'][data-part='root'] {
15
+ /* 交叉轴对齐收在两个私有槽里:缺省那一支跟着当档的方向走,写了 align 的档改的是另一支。
16
+ 分两支是因为逐档切方向时,缺省对齐要跟着换,而作者显式写的对齐不能被换掉。
17
+ 每一层都声明一遍,嵌套时内层不吃外层的值 */
18
+ --xh-_flex-align-default: center;
19
+ --xh-_flex-align: var(--xh-_flex-align-default);
20
+
15
21
  display: flex;
16
22
  flex-wrap: nowrap;
23
+ align-items: var(--xh-_flex-align);
17
24
  /* 不写 gap 档位就不留间距;使用者槽位排在档位之前,写死一个值即盖过所有档 */
18
25
  gap: var(--xh-flex-gap, var(--xh-space-0));
19
26
  }
@@ -34,13 +41,13 @@
34
41
  /* 横排时按中线对齐:一排里混着文字、按钮、标签,高度本就不齐,居中最不容易看出错位 */
35
42
  [data-scope='flex'][data-part='root'][data-orientation='horizontal'] {
36
43
  flex-direction: row;
37
- align-items: center;
44
+ --xh-_flex-align-default: center;
38
45
  }
39
46
 
40
47
  /* 竖排时拉伸:一列里的块级子项该占满容器宽度 */
41
48
  [data-scope='flex'][data-part='root'][data-orientation='vertical'] {
42
49
  flex-direction: column;
43
- align-items: stretch;
50
+ --xh-_flex-align-default: stretch;
44
51
  }
45
52
 
46
53
  /* —— 折行 —— */
@@ -49,25 +56,25 @@
49
56
  }
50
57
 
51
58
  /* —— 交叉轴对齐 —— */
52
- /* 排在方向之后:两者特指度相同,写了 align 就该压过随方向来的那份缺省 */
59
+ /* 写的是显式那一支:特指度比根上那条缺省高,方向怎么换都盖不掉它 */
53
60
  [data-scope='flex'][data-part='root'][data-align='start'] {
54
- align-items: flex-start;
61
+ --xh-_flex-align: flex-start;
55
62
  }
56
63
 
57
64
  [data-scope='flex'][data-part='root'][data-align='center'] {
58
- align-items: center;
65
+ --xh-_flex-align: center;
59
66
  }
60
67
 
61
68
  [data-scope='flex'][data-part='root'][data-align='end'] {
62
- align-items: flex-end;
69
+ --xh-_flex-align: flex-end;
63
70
  }
64
71
 
65
72
  [data-scope='flex'][data-part='root'][data-align='stretch'] {
66
- align-items: stretch;
73
+ --xh-_flex-align: stretch;
67
74
  }
68
75
 
69
76
  [data-scope='flex'][data-part='root'][data-align='baseline'] {
70
- align-items: baseline;
77
+ --xh-_flex-align: baseline;
71
78
  }
72
79
 
73
80
  /* —— 主轴分布 —— */
@@ -117,6 +124,315 @@
117
124
  gap: var(--xh-flex-gap, var(--xh-layout-gap-xl));
118
125
  }
119
126
 
127
+ /* —— 逐档的方向、对齐、分布与间距 —— */
128
+ /* 移动优先:先按不带档位的那几个属性排定,视口每宽到一档就换成那一档的取值,没写的档沿用比它窄的那一档。
129
+ 四档自窄到宽依次写,只用 min-width:媒体查询不改选择器权重,宽视口上同时命中好几档时由源码序决定谁生效。
130
+ 宽度写字面量:自定义属性在 @media 条件里不参与求值,令牌变量写在这里等于没写条件。
131
+ 方向换档时只换缺省对齐那一支,作者写过的对齐仍由显式那一支说了算 */
132
+ @media (min-width: 640px) {
133
+ [data-scope='flex'][data-part='root'][data-orientation-sm='horizontal'] {
134
+ flex-direction: row;
135
+ --xh-_flex-align-default: center;
136
+ }
137
+
138
+ [data-scope='flex'][data-part='root'][data-orientation-sm='vertical'] {
139
+ flex-direction: column;
140
+ --xh-_flex-align-default: stretch;
141
+ }
142
+
143
+ [data-scope='flex'][data-part='root'][data-align-sm='start'] {
144
+ --xh-_flex-align: flex-start;
145
+ }
146
+
147
+ [data-scope='flex'][data-part='root'][data-align-sm='center'] {
148
+ --xh-_flex-align: center;
149
+ }
150
+
151
+ [data-scope='flex'][data-part='root'][data-align-sm='end'] {
152
+ --xh-_flex-align: flex-end;
153
+ }
154
+
155
+ [data-scope='flex'][data-part='root'][data-align-sm='stretch'] {
156
+ --xh-_flex-align: stretch;
157
+ }
158
+
159
+ [data-scope='flex'][data-part='root'][data-align-sm='baseline'] {
160
+ --xh-_flex-align: baseline;
161
+ }
162
+
163
+ [data-scope='flex'][data-part='root'][data-justify-sm='start'] {
164
+ justify-content: flex-start;
165
+ }
166
+
167
+ [data-scope='flex'][data-part='root'][data-justify-sm='center'] {
168
+ justify-content: center;
169
+ }
170
+
171
+ [data-scope='flex'][data-part='root'][data-justify-sm='end'] {
172
+ justify-content: flex-end;
173
+ }
174
+
175
+ [data-scope='flex'][data-part='root'][data-justify-sm='between'] {
176
+ justify-content: space-between;
177
+ }
178
+
179
+ [data-scope='flex'][data-part='root'][data-justify-sm='around'] {
180
+ justify-content: space-around;
181
+ }
182
+
183
+ [data-scope='flex'][data-part='root'][data-justify-sm='evenly'] {
184
+ justify-content: space-evenly;
185
+ }
186
+
187
+ [data-scope='flex'][data-part='root'][data-gap-sm='xs'] {
188
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xs));
189
+ }
190
+
191
+ [data-scope='flex'][data-part='root'][data-gap-sm='sm'] {
192
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-sm));
193
+ }
194
+
195
+ [data-scope='flex'][data-part='root'][data-gap-sm='md'] {
196
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-md));
197
+ }
198
+
199
+ [data-scope='flex'][data-part='root'][data-gap-sm='lg'] {
200
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-lg));
201
+ }
202
+
203
+ [data-scope='flex'][data-part='root'][data-gap-sm='xl'] {
204
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xl));
205
+ }
206
+ }
207
+
208
+ @media (min-width: 768px) {
209
+ [data-scope='flex'][data-part='root'][data-orientation-md='horizontal'] {
210
+ flex-direction: row;
211
+ --xh-_flex-align-default: center;
212
+ }
213
+
214
+ [data-scope='flex'][data-part='root'][data-orientation-md='vertical'] {
215
+ flex-direction: column;
216
+ --xh-_flex-align-default: stretch;
217
+ }
218
+
219
+ [data-scope='flex'][data-part='root'][data-align-md='start'] {
220
+ --xh-_flex-align: flex-start;
221
+ }
222
+
223
+ [data-scope='flex'][data-part='root'][data-align-md='center'] {
224
+ --xh-_flex-align: center;
225
+ }
226
+
227
+ [data-scope='flex'][data-part='root'][data-align-md='end'] {
228
+ --xh-_flex-align: flex-end;
229
+ }
230
+
231
+ [data-scope='flex'][data-part='root'][data-align-md='stretch'] {
232
+ --xh-_flex-align: stretch;
233
+ }
234
+
235
+ [data-scope='flex'][data-part='root'][data-align-md='baseline'] {
236
+ --xh-_flex-align: baseline;
237
+ }
238
+
239
+ [data-scope='flex'][data-part='root'][data-justify-md='start'] {
240
+ justify-content: flex-start;
241
+ }
242
+
243
+ [data-scope='flex'][data-part='root'][data-justify-md='center'] {
244
+ justify-content: center;
245
+ }
246
+
247
+ [data-scope='flex'][data-part='root'][data-justify-md='end'] {
248
+ justify-content: flex-end;
249
+ }
250
+
251
+ [data-scope='flex'][data-part='root'][data-justify-md='between'] {
252
+ justify-content: space-between;
253
+ }
254
+
255
+ [data-scope='flex'][data-part='root'][data-justify-md='around'] {
256
+ justify-content: space-around;
257
+ }
258
+
259
+ [data-scope='flex'][data-part='root'][data-justify-md='evenly'] {
260
+ justify-content: space-evenly;
261
+ }
262
+
263
+ [data-scope='flex'][data-part='root'][data-gap-md='xs'] {
264
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xs));
265
+ }
266
+
267
+ [data-scope='flex'][data-part='root'][data-gap-md='sm'] {
268
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-sm));
269
+ }
270
+
271
+ [data-scope='flex'][data-part='root'][data-gap-md='md'] {
272
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-md));
273
+ }
274
+
275
+ [data-scope='flex'][data-part='root'][data-gap-md='lg'] {
276
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-lg));
277
+ }
278
+
279
+ [data-scope='flex'][data-part='root'][data-gap-md='xl'] {
280
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xl));
281
+ }
282
+ }
283
+
284
+ @media (min-width: 1024px) {
285
+ [data-scope='flex'][data-part='root'][data-orientation-lg='horizontal'] {
286
+ flex-direction: row;
287
+ --xh-_flex-align-default: center;
288
+ }
289
+
290
+ [data-scope='flex'][data-part='root'][data-orientation-lg='vertical'] {
291
+ flex-direction: column;
292
+ --xh-_flex-align-default: stretch;
293
+ }
294
+
295
+ [data-scope='flex'][data-part='root'][data-align-lg='start'] {
296
+ --xh-_flex-align: flex-start;
297
+ }
298
+
299
+ [data-scope='flex'][data-part='root'][data-align-lg='center'] {
300
+ --xh-_flex-align: center;
301
+ }
302
+
303
+ [data-scope='flex'][data-part='root'][data-align-lg='end'] {
304
+ --xh-_flex-align: flex-end;
305
+ }
306
+
307
+ [data-scope='flex'][data-part='root'][data-align-lg='stretch'] {
308
+ --xh-_flex-align: stretch;
309
+ }
310
+
311
+ [data-scope='flex'][data-part='root'][data-align-lg='baseline'] {
312
+ --xh-_flex-align: baseline;
313
+ }
314
+
315
+ [data-scope='flex'][data-part='root'][data-justify-lg='start'] {
316
+ justify-content: flex-start;
317
+ }
318
+
319
+ [data-scope='flex'][data-part='root'][data-justify-lg='center'] {
320
+ justify-content: center;
321
+ }
322
+
323
+ [data-scope='flex'][data-part='root'][data-justify-lg='end'] {
324
+ justify-content: flex-end;
325
+ }
326
+
327
+ [data-scope='flex'][data-part='root'][data-justify-lg='between'] {
328
+ justify-content: space-between;
329
+ }
330
+
331
+ [data-scope='flex'][data-part='root'][data-justify-lg='around'] {
332
+ justify-content: space-around;
333
+ }
334
+
335
+ [data-scope='flex'][data-part='root'][data-justify-lg='evenly'] {
336
+ justify-content: space-evenly;
337
+ }
338
+
339
+ [data-scope='flex'][data-part='root'][data-gap-lg='xs'] {
340
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xs));
341
+ }
342
+
343
+ [data-scope='flex'][data-part='root'][data-gap-lg='sm'] {
344
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-sm));
345
+ }
346
+
347
+ [data-scope='flex'][data-part='root'][data-gap-lg='md'] {
348
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-md));
349
+ }
350
+
351
+ [data-scope='flex'][data-part='root'][data-gap-lg='lg'] {
352
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-lg));
353
+ }
354
+
355
+ [data-scope='flex'][data-part='root'][data-gap-lg='xl'] {
356
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xl));
357
+ }
358
+ }
359
+
360
+ @media (min-width: 1280px) {
361
+ [data-scope='flex'][data-part='root'][data-orientation-xl='horizontal'] {
362
+ flex-direction: row;
363
+ --xh-_flex-align-default: center;
364
+ }
365
+
366
+ [data-scope='flex'][data-part='root'][data-orientation-xl='vertical'] {
367
+ flex-direction: column;
368
+ --xh-_flex-align-default: stretch;
369
+ }
370
+
371
+ [data-scope='flex'][data-part='root'][data-align-xl='start'] {
372
+ --xh-_flex-align: flex-start;
373
+ }
374
+
375
+ [data-scope='flex'][data-part='root'][data-align-xl='center'] {
376
+ --xh-_flex-align: center;
377
+ }
378
+
379
+ [data-scope='flex'][data-part='root'][data-align-xl='end'] {
380
+ --xh-_flex-align: flex-end;
381
+ }
382
+
383
+ [data-scope='flex'][data-part='root'][data-align-xl='stretch'] {
384
+ --xh-_flex-align: stretch;
385
+ }
386
+
387
+ [data-scope='flex'][data-part='root'][data-align-xl='baseline'] {
388
+ --xh-_flex-align: baseline;
389
+ }
390
+
391
+ [data-scope='flex'][data-part='root'][data-justify-xl='start'] {
392
+ justify-content: flex-start;
393
+ }
394
+
395
+ [data-scope='flex'][data-part='root'][data-justify-xl='center'] {
396
+ justify-content: center;
397
+ }
398
+
399
+ [data-scope='flex'][data-part='root'][data-justify-xl='end'] {
400
+ justify-content: flex-end;
401
+ }
402
+
403
+ [data-scope='flex'][data-part='root'][data-justify-xl='between'] {
404
+ justify-content: space-between;
405
+ }
406
+
407
+ [data-scope='flex'][data-part='root'][data-justify-xl='around'] {
408
+ justify-content: space-around;
409
+ }
410
+
411
+ [data-scope='flex'][data-part='root'][data-justify-xl='evenly'] {
412
+ justify-content: space-evenly;
413
+ }
414
+
415
+ [data-scope='flex'][data-part='root'][data-gap-xl='xs'] {
416
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xs));
417
+ }
418
+
419
+ [data-scope='flex'][data-part='root'][data-gap-xl='sm'] {
420
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-sm));
421
+ }
422
+
423
+ [data-scope='flex'][data-part='root'][data-gap-xl='md'] {
424
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-md));
425
+ }
426
+
427
+ [data-scope='flex'][data-part='root'][data-gap-xl='lg'] {
428
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-lg));
429
+ }
430
+
431
+ [data-scope='flex'][data-part='root'][data-gap-xl='xl'] {
432
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xl));
433
+ }
434
+ }
435
+
120
436
  /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
121
437
  写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
122
438
  [data-scope='flex'][data-part='root'][hidden] {
@@ -9,6 +9,7 @@
9
9
 
10
10
  /* 共享关键帧由 family/motion.css 提供,本皮肤 @import 它,单独引入仍成立。 */
11
11
  @import '../family/motion.css';
12
+ @import '../family/material.css';
12
13
 
13
14
  @layer xihan.components {
14
15
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
@@ -84,7 +85,7 @@
84
85
  /* —— 形态:给展开列表里原生动作项用的面 ——
85
86
  触发器的面由 Action Control 形态矩阵按 data-xh-action-variant 给(solid / subtle / ghost),
86
87
  原生动作项读不到矩阵,这几块私有槽按矩阵同一张表镜像;ghost 与 outline 的悬停 / 按下走画布承载的
87
- 阶梯(100 → 200,§7.2 第 3 条)。缺省 outline(连接层不传 variant 时显式落)是磨砂面:背景、边缘、
88
+ 阶梯(100 → 200)。缺省 outline(连接层不传 variant 时显式落)是磨砂面:背景、边缘、
88
89
  顶光、投影与磨砂从同一份 M2 配方取,高对比、减少透明度、打印和强制色便能一起降级——钮浮在正文
89
90
  之上,透空的面在任何内容上都读不出边界,所以 outline 这一档面留着 */
90
91
  [data-scope='float-button'][data-part='root'][data-variant='solid'] {
@@ -97,10 +98,11 @@
97
98
  --xh-_float-button-shadow: none;
98
99
  }
99
100
 
101
+ /* 浮动钮钉在内容之上,面要盖得住底下的内容:没写语气时淡底取不透明档(ghost 静息就透景,不在此列) */
100
102
  [data-scope='float-button'][data-part='root'][data-variant='subtle'] {
101
- --xh-_float-button-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle));
102
- --xh-_float-button-bg-hover: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover));
103
- --xh-_float-button-bg-active: var(--xh-_tone-subtle-active, var(--xh-bg-subtle-active));
103
+ --xh-_float-button-bg: var(--xh-_tone-subtle, var(--xh-bg-subtle-opaque));
104
+ --xh-_float-button-bg-hover: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover-opaque));
105
+ --xh-_float-button-bg-active: var(--xh-_tone-subtle-active, var(--xh-bg-subtle-active-opaque));
104
106
  --xh-_float-button-fg: var(--xh-_tone-fg, var(--xh-fg-default));
105
107
  --xh-_float-button-border: transparent;
106
108
  --xh-_float-button-border-hover: transparent;
@@ -109,8 +111,8 @@
109
111
 
110
112
  [data-scope='float-button'][data-part='root'][data-variant='outline'] {
111
113
  --xh-_float-button-bg: var(--xh-material-frosted-bg);
112
- --xh-_float-button-bg-hover: var(--xh-_tone-subtle, var(--xh-bg-subtle));
113
- --xh-_float-button-bg-active: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover));
114
+ --xh-_float-button-bg-hover: var(--xh-_tone-subtle, var(--xh-bg-subtle-opaque));
115
+ --xh-_float-button-bg-active: var(--xh-_tone-subtle-hover, var(--xh-bg-subtle-hover-opaque));
114
116
  --xh-_float-button-fg: var(--xh-material-frosted-fg);
115
117
  --xh-_float-button-border: var(--xh-material-frosted-border);
116
118
  --xh-_float-button-border-hover: var(--xh-material-frosted-border);
@@ -128,7 +130,7 @@
128
130
  }
129
131
 
130
132
  /* —— 触发器 ——
131
- 浮在内容之上的单图标圆钮,接 Action Control floating 档(§4.1):盒型(md = box-lg 48px,圆形)、
133
+ 浮在内容之上的单图标圆钮,接 Action Control floating 档:盒型(md = box-lg 48px,圆形)、
132
134
  四态面、0.97 按压与 44px 命中区由家族配方按 data-xh-action-variant / -size 给出。
133
135
  这里只把公开槽桥接到矩阵之前(使用者槽 → 形态矩阵 → 家族缺省)与几何槽映射 */
134
136
  [data-scope='float-button'][data-part='trigger'] {
@@ -146,7 +148,7 @@
146
148
  --xh-action-border-pressed: var(--xh-float-button-border-hover, var(--xh-_action-variant-border-pressed));
147
149
  --xh-action-border-focus-visible: var(--xh-float-button-border, var(--xh-_action-variant-border-focus-visible));
148
150
  --xh-action-border-disabled: var(--xh-float-button-border, var(--xh-_action-variant-border-disabled));
149
- /* 矩阵各态无影(§8.3 淡底与阴影互斥);outline 那一档的磨砂投影在下面另桥接 */
151
+ /* 矩阵各态无影(淡底与阴影互斥);outline 那一档的磨砂投影在下面另桥接 */
150
152
  --xh-action-shadow-rest: var(--xh-float-button-shadow, none);
151
153
  --xh-action-shadow-hover: var(--xh-float-button-shadow, none);
152
154
  --xh-action-shadow-pressed: var(--xh-float-button-shadow, none);
@@ -158,38 +160,114 @@
158
160
  --xh-icon-size: var(--xh-float-button-icon-size, var(--xh-_action-profile-glyph-size));
159
161
  }
160
162
 
161
- /* 缺省 outline 是 M2 磨砂面:背景、边缘、顶光、投影与磨砂从同一份配方取。
162
- 悬停 / 按下的底走矩阵 outline 列的画布阶梯(100 → 200),边缘与投影不动;
163
- 键盘聚焦时铺配方的实体 focus surface——透明面上的内收环没有稳定的底可量对比;
164
- 置灰只换字色(矩阵 disabled 列的前景),面仍留着,透空的面在任何内容上都读不出边界 */
163
+ /* 缺省 outline 是 frosted 材质面:连接层只在这一档投影 data-xh-material,面由材质家族配方给——
164
+ 底、描边、投影、1px 顶光与背景滤镜一份取值,高对比、减少透明度、打印和强制色沿同一令牌通道降级。
165
+ 悬停 / 按下换不透明的淡底一档、二档,边缘与投影不动;键盘聚焦时铺实体 focus surface——透明面上的
166
+ 内收环不能依赖页面底色;置灰只换字色,面仍留着,透空的面在任何内容上都读不出边界 */
165
167
  [data-scope='float-button'][data-part='root'][data-variant='outline']
166
168
  [data-scope='float-button'][data-part='trigger'] {
167
- --xh-action-bg-rest: var(--xh-float-button-bg, var(--xh-_float-button-bg));
168
- --xh-action-bg-focus-visible: var(--xh-float-button-bg, var(--xh-material-frosted-focus-surface));
169
- --xh-action-bg-disabled: var(--xh-float-button-bg, var(--xh-_float-button-bg));
170
- --xh-action-fg-rest: var(--xh-float-button-fg, var(--xh-_float-button-fg));
171
- --xh-action-fg-hover: var(--xh-float-button-fg, var(--xh-_float-button-fg));
172
- --xh-action-fg-pressed: var(--xh-float-button-fg, var(--xh-_float-button-fg));
173
- --xh-action-fg-focus-visible: var(--xh-float-button-fg, var(--xh-_float-button-fg));
174
- --xh-action-border-rest: var(--xh-float-button-border, var(--xh-_float-button-border));
175
- --xh-action-border-hover: var(--xh-float-button-border-hover, var(--xh-_float-button-border-hover));
176
- --xh-action-border-pressed: var(--xh-float-button-border-hover, var(--xh-_float-button-border-hover));
177
- --xh-action-border-focus-visible: var(--xh-float-button-border, var(--xh-_float-button-border));
178
- --xh-action-border-disabled: var(--xh-float-button-border, var(--xh-_float-button-border));
179
- --xh-action-shadow-rest: var(--xh-float-button-shadow, var(--xh-_float-button-shadow));
180
- --xh-action-shadow-hover: var(--xh-float-button-shadow, var(--xh-_float-button-shadow));
181
- --xh-action-shadow-pressed: var(--xh-float-button-shadow, var(--xh-_float-button-shadow));
182
- --xh-action-shadow-focus-visible: var(--xh-float-button-shadow, var(--xh-_float-button-shadow));
183
- --xh-action-shadow-disabled: var(--xh-float-button-shadow, var(--xh-_float-button-shadow));
169
+ /* 面走材质家族配方(family/material.css):frosted 档的底、交互阶梯、描边、投影、1px 顶光与背景滤镜,
170
+ liquid 档由配方换成液态面;这里把使用者槽接到 Action Control 的桥接槽 */
171
+ --xh-action-bg-rest: var(--xh-float-button-bg, var(--xh-_material-bg));
172
+ --xh-action-bg-hover: var(--xh-float-button-bg-hover, var(--xh-_material-bg-hover));
173
+ --xh-action-bg-pressed: var(--xh-float-button-bg-active, var(--xh-_material-bg-pressed));
174
+ --xh-action-bg-focus-visible: var(--xh-float-button-bg, var(--xh-_material-bg-focus));
175
+ --xh-action-bg-disabled: var(--xh-float-button-bg, var(--xh-_material-bg));
176
+ --xh-action-fg-rest: var(--xh-float-button-fg, var(--xh-_material-fg));
177
+ --xh-action-fg-hover: var(--xh-float-button-fg, var(--xh-_material-fg));
178
+ --xh-action-fg-pressed: var(--xh-float-button-fg, var(--xh-_material-fg));
179
+ --xh-action-fg-focus-visible: var(--xh-float-button-fg, var(--xh-_material-fg));
180
+ --xh-action-border-rest: var(--xh-float-button-border, var(--xh-_material-border));
181
+ --xh-action-border-hover: var(--xh-float-button-border-hover, var(--xh-_material-border));
182
+ --xh-action-border-pressed: var(--xh-float-button-border-hover, var(--xh-_material-border));
183
+ --xh-action-border-focus-visible: var(--xh-float-button-border, var(--xh-_material-border));
184
+ --xh-action-border-disabled: var(--xh-float-button-border, var(--xh-_material-border));
185
+ --xh-action-shadow-rest: var(--xh-float-button-shadow, var(--xh-_material-shadow));
186
+ --xh-action-shadow-hover: var(--xh-float-button-shadow, var(--xh-_material-shadow));
187
+ --xh-action-shadow-pressed: var(--xh-float-button-shadow, var(--xh-_material-shadow));
188
+ --xh-action-shadow-focus-visible: var(--xh-float-button-shadow, var(--xh-_material-shadow));
189
+ --xh-action-shadow-disabled: var(--xh-float-button-shadow, var(--xh-_material-shadow));
190
+ --xh-action-highlight-rest: var(--xh-_material-highlight);
191
+ --xh-action-highlight-hover: var(--xh-_material-highlight);
192
+ --xh-action-highlight-pressed: var(--xh-_material-highlight);
193
+ --xh-action-highlight-focus-visible: var(--xh-_material-highlight);
194
+ --xh-action-highlight-disabled: var(--xh-_material-highlight);
184
195
  /* M2 顶光走配方的高光通道:实心、淡色与透空形态各有自身表面,不能把磨砂高光误铺上去 */
185
- --xh-action-highlight-rest: var(--xh-material-frosted-highlight);
186
- --xh-action-highlight-hover: var(--xh-material-frosted-highlight);
187
- --xh-action-highlight-pressed: var(--xh-material-frosted-highlight);
188
- --xh-action-highlight-focus-visible: var(--xh-material-frosted-highlight);
189
- --xh-action-highlight-disabled: var(--xh-material-frosted-highlight);
196
+ }
190
197
 
191
- -webkit-backdrop-filter: var(--xh-material-frosted-backdrop);
192
- backdrop-filter: var(--xh-material-frosted-backdrop);
198
+ /* 液态组:液态档下触发器与展开的动作结成一组(状态机挂进 core),共用宿主最前面那层色块,
199
+ 靠近时边缘像液体一样连起来。底色、墨色细线、亮边与投影都由色块层沿整组的外形画,块自己的面与细线
200
+ 换成透明、亮边与投影撤掉,只留磨砂;悬停 / 按下改成往前景色兑的一层薄色叠在色块上。
201
+ 只有缺省 outline 的液态面才结组,其余形态的面是实心的,色块层藏起来。强制色下色块层撤掉,块保留原样 */
202
+ @media (forced-colors: none) {
203
+ :where([data-material='liquid']) [data-scope='float-button'][data-part='root'][data-variant='outline'][data-xh-liquid-goo]
204
+ [data-scope='float-button'][data-part='trigger'][data-xh-liquid] {
205
+ --xh-action-bg-rest: var(--xh-float-button-bg, transparent);
206
+ --xh-action-bg-hover: var(--xh-float-button-bg-hover, color-mix(in oklab, var(--xh-material-liquid-fg) 8%, transparent));
207
+ --xh-action-bg-pressed: var(--xh-float-button-bg-active, color-mix(in oklab, var(--xh-material-liquid-fg) 14%, transparent));
208
+ --xh-action-bg-disabled: var(--xh-float-button-bg, transparent);
209
+ --xh-action-border-rest: var(--xh-float-button-border, transparent);
210
+ --xh-action-border-hover: var(--xh-float-button-border-hover, transparent);
211
+ --xh-action-border-pressed: var(--xh-float-button-border-hover, transparent);
212
+ --xh-action-border-focus-visible: var(--xh-float-button-border, transparent);
213
+ --xh-action-border-disabled: var(--xh-float-button-border, transparent);
214
+ --xh-action-shadow-rest: none;
215
+ --xh-action-shadow-hover: none;
216
+ --xh-action-shadow-pressed: none;
217
+ --xh-action-shadow-focus-visible: none;
218
+ --xh-action-shadow-disabled: none;
219
+ }
220
+ }
221
+
222
+ [data-scope='float-button'][data-part='root']:not([data-variant='outline']) > [data-xh-liquid-goo-layer] {
223
+ display: none;
224
+ }
225
+
226
+ /* 整组的投影由色块层沿外形画,使用者的投影槽接到那里。色块层不是部件,只按 scope 选 */
227
+ [data-scope='float-button'] > [data-xh-liquid-goo-layer] {
228
+ --xh-_liquid-goo-shadow: var(--xh-float-button-shadow, var(--xh-material-liquid-shadow));
229
+ }
230
+
231
+ /* 色块层不设层号、靠排在最前压在各块之下:展开组也得是定位元素才盖得住它(触发器本就是) */
232
+ [data-scope='float-button'][data-part='root'][data-xh-liquid-goo] [data-scope='float-button'][data-part='list'] {
233
+ position: relative;
234
+ }
235
+
236
+ /* 展开组里的原生动作项在组里同样是液态面:底色、细线、亮边与投影交给色块层,块上留前景与磨砂 */
237
+ @media (forced-colors: none) {
238
+ :where([data-material='liquid']) [data-scope='float-button'][data-part='root'][data-variant='outline'][data-xh-liquid-goo]
239
+ [data-scope='float-button'][data-part='list']
240
+ > button:not([data-scope]) {
241
+ border-color: var(--xh-float-button-border, transparent);
242
+ background-color: var(--xh-float-button-bg, transparent);
243
+ background-image: none;
244
+ color: var(--xh-float-button-fg, var(--xh-material-liquid-fg));
245
+ box-shadow: none;
246
+ -webkit-backdrop-filter: var(--xh-material-liquid-backdrop);
247
+ backdrop-filter: var(--xh-material-liquid-backdrop);
248
+ }
249
+ }
250
+
251
+ @media (forced-colors: none) and (hover: hover) {
252
+ :where([data-material='liquid']) [data-scope='float-button'][data-part='root'][data-variant='outline'][data-xh-liquid-goo]
253
+ [data-scope='float-button'][data-part='list']
254
+ > button:not([data-scope]):not(:disabled):hover {
255
+ border-color: var(--xh-float-button-border-hover, transparent);
256
+ background-color: var(--xh-float-button-bg-hover, color-mix(in oklab, var(--xh-material-liquid-fg) 8%, transparent));
257
+ }
258
+ }
259
+
260
+ @media (forced-colors: none) {
261
+ :where([data-material='liquid']) [data-scope='float-button'][data-part='root'][data-variant='outline'][data-xh-liquid-goo]
262
+ [data-scope='float-button'][data-part='list']
263
+ > button:not([data-scope]):not(:disabled):active {
264
+ background-color: var(--xh-float-button-bg-active, color-mix(in oklab, var(--xh-material-liquid-fg) 14%, transparent));
265
+ }
266
+ }
267
+
268
+ /* 从触发器里分离、融回的那几块由液态组的弹簧逐帧写姿态,CSS 的逐条冒出不再叠上去 */
269
+ [data-scope='float-button'][data-part='list'] > [data-xh-liquid-goo-split] {
270
+ animation: none;
193
271
  }
194
272
 
195
273
  /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
@@ -223,7 +301,12 @@
223
301
  inline-size: var(--xh-float-button-size, var(--xh-_float-button-size));
224
302
  block-size: var(--xh-float-button-size, var(--xh-_float-button-size));
225
303
  border-radius: var(--xh-float-button-radius, var(--xh-shape-circle));
226
- /* 逐条依次冒出来,离触发器最近的那条先到。backwards 让每条在自己那份延迟里保持起始帧 */
304
+ }
305
+
306
+ /* 逐条依次冒出来,离触发器最近的那条先到。backwards 让每条在自己那份延迟里保持起始帧。
307
+ 挂载时就展开着的那一段(data-instant)属于首帧,直接呈现。守卫包在 :where 里不加特异性:
308
+ 后面的交错延迟、液态分离块与收起那几条要照旧压得过这一条 */
309
+ [data-scope='float-button'][data-part='list']:where(:not([data-instant])) > * {
227
310
  animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter-strong) backwards;
228
311
  }
229
312
 
@@ -278,7 +361,7 @@
278
361
  cursor: not-allowed;
279
362
  }
280
363
 
281
- /* 交错的间隔:第二条起逐级往后推,第六条起统一钉在第五级,
364
+ /* 交错的间隔:第二条起逐级往后推,第五条起统一钉在第四级——与收起、与列表动效同一个封顶,
282
365
  动作再多也不会拖出一条越来越慢的尾巴 */
283
366
  [data-scope='float-button'][data-part='list'] > *:nth-child(2) {
284
367
  animation-delay: var(--xh-motion-stagger-step);
@@ -292,12 +375,31 @@
292
375
  animation-delay: calc(3 * var(--xh-motion-stagger-step));
293
376
  }
294
377
 
295
- [data-scope='float-button'][data-part='list'] > *:nth-child(5) {
378
+ [data-scope='float-button'][data-part='list'] > *:nth-child(n + 5) {
296
379
  animation-delay: calc(4 * var(--xh-motion-stagger-step));
297
380
  }
298
381
 
299
- [data-scope='float-button'][data-part='list'] > *:nth-child(n + 6) {
300
- animation-delay: calc(5 * var(--xh-motion-stagger-step));
382
+ /* 收起:逆着冒出的次序逐条缩回,离触发器最远的先走、最近的最后收,连接层等它们播完才藏起展开组。
383
+ 液态档里从触发器拆出来的那几块由液态组融回,不挂这段 */
384
+ [data-scope='float-button'][data-part='list'][data-state='closed'] > :not([data-xh-liquid-goo-split]) {
385
+ pointer-events: none;
386
+ animation: xh-pop-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
387
+ }
388
+
389
+ [data-scope='float-button'][data-part='list'][data-state='closed'] > :not([data-xh-liquid-goo-split]):nth-last-child(2) {
390
+ animation-delay: var(--xh-motion-stagger-step);
391
+ }
392
+
393
+ [data-scope='float-button'][data-part='list'][data-state='closed'] > :not([data-xh-liquid-goo-split]):nth-last-child(3) {
394
+ animation-delay: calc(2 * var(--xh-motion-stagger-step));
395
+ }
396
+
397
+ [data-scope='float-button'][data-part='list'][data-state='closed'] > :not([data-xh-liquid-goo-split]):nth-last-child(4) {
398
+ animation-delay: calc(3 * var(--xh-motion-stagger-step));
399
+ }
400
+
401
+ [data-scope='float-button'][data-part='list'][data-state='closed'] > :not([data-xh-liquid-goo-split]):nth-last-child(n + 5) {
402
+ animation-delay: calc(4 * var(--xh-motion-stagger-step));
301
403
  }
302
404
 
303
405
  /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中。
@@ -311,6 +413,12 @@
311
413
  background-color: currentColor;
312
414
  -webkit-mask: var(--xh-glyph-mark-plus) center / contain no-repeat;
313
415
  mask: var(--xh-glyph-mark-plus) center / contain no-repeat;
416
+ /* 原地的小幅转动:展开后「+」转 45° 成「×」,读得出再按一下就收起;减弱动效下即刻到位 */
417
+ transition: rotate var(--xh-motion-duration-nudge) var(--xh-motion-ease-enter-strong);
418
+ }
419
+
420
+ [data-scope='float-button'][data-part='trigger'][data-state='open']:empty::before {
421
+ rotate: 45deg;
314
422
  }
315
423
 
316
424
  /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
@@ -326,4 +434,23 @@
326
434
  display: none;
327
435
  }
328
436
  }
437
+
438
+ @media (forced-colors: active) {
439
+ /* 兜底字形是 mask 挖出来的一块底色,这一档里底色被系统换成 Canvas,字形跟着消失。
440
+ 字形退出强制换色、直接写系统色(不能取 currentColor:退出强制换色的伪元素读到的是被系统换掉之前的作者色):
441
+ 按钮面上取 ButtonText,悬停与按下时家族把按钮涂成 Highlight、字形换 HighlightText;
442
+ 禁用取 GrayText */
443
+ [data-scope='float-button'][data-part='trigger']:empty::before {
444
+ forced-color-adjust: none;
445
+ background-color: ButtonText;
446
+ }
447
+
448
+ [data-scope='float-button'][data-part='trigger']:not([data-disabled]):not([data-loading]):is(:hover, :active, [data-pressed]):empty::before {
449
+ background-color: HighlightText;
450
+ }
451
+
452
+ [data-scope='float-button'][data-part='trigger'][data-disabled]:empty::before {
453
+ background-color: GrayText;
454
+ }
455
+ }
329
456
  }