@xihan-ui/styles 2.1.0 → 3.1.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 (152) hide show
  1. package/CHANGELOG.md +1261 -0
  2. package/README.md +6 -1
  3. package/component-tokens.d.ts +533 -96
  4. package/components.tokens.json +35461 -26045
  5. package/css/accordion.css +34 -8
  6. package/css/alert.css +59 -1
  7. package/css/anchor.css +46 -8
  8. package/css/approval.css +116 -76
  9. package/css/avatar-group.css +1 -1
  10. package/css/avatar.css +13 -5
  11. package/css/back-top.css +61 -42
  12. package/css/badge.css +62 -12
  13. package/css/bar-code.css +1 -1
  14. package/css/breadcrumb.css +62 -3
  15. package/css/button-group.css +4 -4
  16. package/css/button.css +67 -19
  17. package/css/calendar-picker.css +19 -0
  18. package/css/calendar-range-picker.css +39 -2
  19. package/css/card.css +115 -1
  20. package/css/carousel.css +148 -43
  21. package/css/cartesian-chart.css +830 -0
  22. package/css/cascader.css +181 -65
  23. package/css/checkbox-group.css +59 -89
  24. package/css/checkbox.css +16 -49
  25. package/css/citation.css +470 -0
  26. package/css/clipboard.css +20 -63
  27. package/css/code-view.css +101 -6
  28. package/css/collapsible.css +34 -8
  29. package/css/color-field.css +18 -0
  30. package/css/color-picker.css +128 -50
  31. package/css/color-slider.css +22 -15
  32. package/css/color-swatch-picker.css +3 -1
  33. package/css/combobox.css +80 -33
  34. package/css/command.css +45 -43
  35. package/css/context-menu.css +39 -22
  36. package/css/date-field.css +56 -0
  37. package/css/date-picker.css +132 -26
  38. package/css/date-range-picker.css +337 -14
  39. package/css/description.css +17 -1
  40. package/css/descriptions.css +42 -0
  41. package/css/dialog.css +94 -36
  42. package/css/diff-view.css +97 -12
  43. package/css/download-trigger.css +44 -78
  44. package/css/drawer.css +160 -119
  45. package/css/editable.css +19 -0
  46. package/css/empty-state.css +7 -6
  47. package/css/field-array.css +36 -0
  48. package/css/field.css +20 -18
  49. package/css/file-upload.css +125 -135
  50. package/css/flex.css +324 -8
  51. package/css/float-button.css +263 -38
  52. package/css/floating-panel.css +53 -19
  53. package/css/form.css +31 -17
  54. package/css/funnel-chart.css +106 -0
  55. package/css/graph-chart.css +205 -0
  56. package/css/grid-list.css +235 -0
  57. package/css/grid.css +252 -1
  58. package/css/heatmap.css +119 -36
  59. package/css/hierarchy-chart.css +298 -0
  60. package/css/hover-card.css +31 -14
  61. package/css/icon.css +100 -0
  62. package/css/image-cropper.css +33 -7
  63. package/css/image-viewer.css +167 -22
  64. package/css/image.css +23 -4
  65. package/css/input-group.css +11 -13
  66. package/css/json-viewer.css +50 -2
  67. package/css/layout.css +68 -18
  68. package/css/liquid.css +106 -0
  69. package/css/list.css +1 -1
  70. package/css/listbox.css +46 -6
  71. package/css/loading-bar.css +27 -13
  72. package/css/log.css +129 -33
  73. package/css/markdown-stream.css +1 -1
  74. package/css/marquee.css +163 -7
  75. package/css/matrix-code.css +1 -1
  76. package/css/mention.css +35 -19
  77. package/css/menu.css +35 -21
  78. package/css/menubar.css +36 -20
  79. package/css/message-feed.css +172 -51
  80. package/css/navigation-menu.css +172 -11
  81. package/css/notification.css +435 -108
  82. package/css/number-field.css +22 -0
  83. package/css/page-header.css +3 -1
  84. package/css/pagination.css +126 -24
  85. package/css/password-input.css +40 -8
  86. package/css/pie-chart.css +247 -0
  87. package/css/popconfirm.css +44 -50
  88. package/css/popover.css +50 -14
  89. package/css/progress.css +308 -10
  90. package/css/prompt-input.css +36 -0
  91. package/css/question-flow.css +97 -57
  92. package/css/radar-chart.css +233 -0
  93. package/css/radio-group.css +363 -5
  94. package/css/rating.css +21 -23
  95. package/css/reasoning.css +61 -54
  96. package/css/resizable.css +6 -1
  97. package/css/sankey-chart.css +174 -0
  98. package/css/scroll-area.css +32 -0
  99. package/css/scrollbar.css +1 -1
  100. package/css/select.css +74 -55
  101. package/css/side-nav.css +173 -24
  102. package/css/signature-pad.css +16 -1
  103. package/css/skeleton.css +13 -14
  104. package/css/slider.css +35 -13
  105. package/css/sortable.css +37 -7
  106. package/css/sparkline.css +164 -0
  107. package/css/spinner.css +50 -22
  108. package/css/splitter.css +7 -1
  109. package/css/statistic.css +10 -0
  110. package/css/steps.css +248 -29
  111. package/css/switch.css +23 -48
  112. package/css/table.css +175 -118
  113. package/css/tabs.css +231 -19
  114. package/css/tag-group.css +27 -3
  115. package/css/tag.css +53 -12
  116. package/css/tags-input.css +40 -3
  117. package/css/text-field.css +19 -0
  118. package/css/time-field.css +20 -1
  119. package/css/time-picker.css +103 -17
  120. package/css/time-range-picker.css +45 -16
  121. package/css/timeline.css +1 -1
  122. package/css/toggle-group.css +4 -4
  123. package/css/toggle.css +4 -3
  124. package/css/tool-call.css +59 -51
  125. package/css/toolbar.css +101 -3
  126. package/css/tooltip.css +15 -2
  127. package/css/tour.css +42 -12
  128. package/css/transfer.css +98 -75
  129. package/css/tree-select.css +232 -53
  130. package/css/tree.css +271 -55
  131. package/css/truncate.css +55 -12
  132. package/css/typography.css +93 -0
  133. package/css/virtualizer.css +56 -0
  134. package/css/watermark.css +23 -0
  135. package/family/action-control.css +14 -5
  136. package/family/chart.css +480 -0
  137. package/family/check-mark.css +94 -0
  138. package/family/choice-card.css +97 -0
  139. package/family/collection-item.css +9 -15
  140. package/family/field-chrome.css +1 -12
  141. package/family/loading-ring.css +95 -0
  142. package/family/material.css +72 -0
  143. package/family/menu-choice.css +56 -0
  144. package/family/motion.css +207 -10
  145. package/family/tag-list.css +59 -0
  146. package/index.css +13824 -4030
  147. package/index.unlayered.css +13403 -3605
  148. package/package.json +20 -8
  149. package/css/gradient-text.css +0 -91
  150. package/css/icon-wrapper.css +0 -81
  151. package/css/segmented.css +0 -280
  152. package/css/toast.css +0 -499
package/css/table.css CHANGED
@@ -6,22 +6,10 @@
6
6
  /* 定义 table 样式。 */
7
7
 
8
8
  @import '../family/action-control.css';
9
+ @import '../family/check-mark.css';
9
10
  @import '../family/collection-item.css';
10
-
11
- @layer xihan.motion {
12
- /* 加载态自己冒出来,用户没按任何键:一段极轻的呼吸就够,别抢走正在读表的注意力 */
13
- /* 一次呼吸自带来回:起止两端与中点各写一帧,声明的周期就是一次完整的明暗往返 */
14
- @keyframes xh-table-loading-pulse {
15
- 0%,
16
- 100% {
17
- opacity: var(--xh-state-disabled-opacity);
18
- }
19
-
20
- 50% {
21
- opacity: 1;
22
- }
23
- }
24
- }
11
+ @import '../family/loading-ring.css';
12
+ @import '../family/motion.css';
25
13
 
26
14
  @layer xihan.components {
27
15
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
@@ -174,6 +162,17 @@
174
162
  display: none;
175
163
  }
176
164
 
165
+ /* 已有行时重新取数(排序、翻页、筛选):不换成占位,表体与表尾保留上一帧,按 micro 淡到禁用透明度,
166
+ 数据到了再淡回。表头留着——它说的是列,不随这一轮取数变 */
167
+ [data-scope='table'][data-part='body'],
168
+ [data-scope='table'][data-part='footer'] {
169
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
170
+ }
171
+
172
+ [data-scope='table'][data-part='root'][data-loading]:not([data-empty]) > :is([data-scope='table'][data-part='body'], [data-scope='table'][data-part='footer']) {
173
+ opacity: var(--xh-state-disabled-opacity);
174
+ }
175
+
177
176
  /* 表体是行级 roving 的兜底 Tab 位:落焦不画环,环归行 */
178
177
  [data-scope='table'][data-part='body']:focus-visible {
179
178
  outline: none;
@@ -185,12 +184,13 @@
185
184
  --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
186
185
  --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
187
186
 
188
- border-block-end: var(--xh-stroke-thin) solid var(--xh-table-border, var(--xh-border-default));
189
- background: var(--xh-table-header-bg, var(--xh-bg-subtle));
187
+ /* 表头与表体之间是内部分隔,与行间横线同一支:外边才取 default */
188
+ border-block-end: var(--xh-stroke-thin) solid var(--xh-table-header-border, var(--xh-border-subtle));
189
+ background: var(--xh-table-header-bg, var(--xh-bg-subtle-opaque));
190
190
  }
191
191
 
192
192
  /* 吸顶:滚动容器是 root,表头钉在它的上沿。背景必须是实色——
193
- 透明的表头会让底下滚过的行透出来 */
193
+ 透明的表头会让底下滚过的行透出来,所以表头底取淡底的不透明档 */
194
194
  [data-scope='table'][data-part='header'][data-fixed] {
195
195
  position: sticky;
196
196
  z-index: var(--xh-table-sticky-header-layer, var(--xh-layer-sticky));
@@ -198,7 +198,8 @@
198
198
  }
199
199
 
200
200
  [data-scope='table'][data-part='footer'] {
201
- border-block-start: var(--xh-stroke-thin) solid var(--xh-table-border, var(--xh-border-default));
201
+ /* 表尾与表体之间同样是内部分隔 */
202
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-table-footer-border, var(--xh-border-subtle));
202
203
  background: var(--xh-table-footer-bg, var(--xh-bg-subtle));
203
204
  font-weight: var(--xh-table-footer-font-weight, var(--xh-font-weight-medium));
204
205
  }
@@ -209,11 +210,12 @@
209
210
  行是 flex 容器(列宽由单元格的内联尺寸决定,不进家族网格)、不内衬、不圆角、字号与光标随表格本身
210
211
  (行不是按钮,selectable 与否都不改光标)。表头 / 脚注行不投影家族,只共用这一副 flex 盒 */
211
212
  [data-scope='table'][data-part='row'] {
212
- /* rest 底要实色:横向吸附的单元格靠 inherit 取它,透明会让滚过的内容透出来 */
213
+ /* 各态的底都要实色:横向吸附的单元格靠 inherit 取它,透明会让滚过的内容透出来。
214
+ 悬停、按下取淡底的不透明档 */
213
215
  --xh-collection-bg-rest: var(--xh-table-row-bg, var(--xh-bg-surface));
214
- --xh-collection-bg-hover: var(--xh-table-row-bg-hover, var(--xh-bg-subtle));
215
- --xh-collection-bg-keyboard-highlight: var(--xh-table-row-bg-hover, var(--xh-bg-subtle));
216
- --xh-collection-bg-pressed: var(--xh-table-row-bg-pressed, var(--xh-bg-subtle-hover));
216
+ --xh-collection-bg-hover: var(--xh-table-row-bg-hover, var(--xh-bg-subtle-opaque));
217
+ --xh-collection-bg-keyboard-highlight: var(--xh-table-row-bg-hover, var(--xh-bg-subtle-opaque));
218
+ --xh-collection-bg-pressed: var(--xh-table-row-bg-pressed, var(--xh-bg-subtle-hover-opaque));
217
219
  --xh-collection-bg-selected: var(--xh-table-row-bg-selected, var(--xh-bg-brand-subtle));
218
220
  --xh-collection-fg-rest: currentColor;
219
221
  --xh-collection-fg-hover: currentColor;
@@ -243,6 +245,12 @@
243
245
  border-radius: 0;
244
246
  /* 文字度量归单元格,行不给行高 */
245
247
  line-height: inherit;
248
+ /* 换面走家族的时间线;translate 是换位提交后的落位:宿主按 ids 重排之后,连接层把行按旧位置反向补偿,
249
+ 这条过渡带它滑到新位置,走完即归零,不常驻变换 */
250
+ transition:
251
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
252
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
253
+ translate var(--xh-motion-duration-move) var(--xh-motion-ease-continuous);
246
254
  }
247
255
 
248
256
  /* 家族给了 display,UA 的 [hidden]{display:none} 已被盖掉 */
@@ -261,7 +269,8 @@
261
269
  --xh-collection-outline-keyboard-highlight: var(--xh-ring-focus);
262
270
  --xh-collection-outline-selected-highlight: var(--xh-ring-focus);
263
271
 
264
- transition: none;
272
+ /* 换面即时,只留换位:Alt + 方向键搬的正是这一行,它照样从旧位置滑到新位置 */
273
+ transition: translate var(--xh-motion-duration-move) var(--xh-motion-ease-continuous);
265
274
  }
266
275
 
267
276
  /* 行间线画在后一行的上沿,区段里第一个可见行不画:行只负责行与行之间,外边界归 root 与区段容器 */
@@ -298,6 +307,23 @@
298
307
  user-select: none;
299
308
  }
300
309
 
310
+ /* 列对齐:data-align 控制列头与数据格的文本与内容对齐方向;
311
+ 显式写出三档以便 start 能重置自定义皮肤里可能存在的非默认对齐 */
312
+ [data-scope='table']:is([data-part='column-header'], [data-part='cell'])[data-align='start'] {
313
+ text-align: start;
314
+ justify-content: start;
315
+ }
316
+
317
+ [data-scope='table']:is([data-part='column-header'], [data-part='cell'])[data-align='center'] {
318
+ text-align: center;
319
+ justify-content: center;
320
+ }
321
+
322
+ [data-scope='table']:is([data-part='column-header'], [data-part='cell'])[data-align='end'] {
323
+ text-align: end;
324
+ justify-content: end;
325
+ }
326
+
301
327
  /* 列名是列头里唯一可收窄的一格:flex: 1 吃掉余量、把排序钮 / 列宽把手推到行尾,min-inline-size: 0 让它在
302
328
  窄列上收得下去并出省略号。列名不能裸写成文本节点:flex 行里的裸文本是匿名 flex item,min-inline-size 取 auto
303
329
  (nowrap 文本的 min-content)缩不下去,96px 的列配一串长列名时定尺的把手连同 auto 外边距一起被挤出列头盒、
@@ -311,6 +337,39 @@
311
337
  white-space: nowrap;
312
338
  }
313
339
 
340
+ /* 纵向合并:起点格(cellSpan 合并的单元格、多级表头里较浅的叶子列头)铺满合并的几行,
341
+ 高度由连接层实测行位后写进私有槽;多出自己那一行的部分用负的下外边距让回去,自己那一行不被撑高。
342
+ 它压在下面几行之上,底色随起点行(表头随表头底),挡住那一列里的行间线。量到之前按普通格子排 */
343
+ [data-scope='table']:is([data-part='cell'], [data-part='column-header'])[data-row-span] {
344
+ /* 缺省即不铺开:连接层量到行位后在内联样式里改写这两支 */
345
+ --xh-_table-span-block: auto;
346
+ --xh-_table-span-overhang: 0px;
347
+
348
+ position: relative;
349
+ z-index: var(--xh-table-span-layer, 1);
350
+ align-self: flex-start;
351
+ block-size: var(--xh-_table-span-block);
352
+ margin-block-end: calc(-1 * var(--xh-_table-span-overhang));
353
+ background: inherit;
354
+ }
355
+
356
+ /* 被合并掉的格子只留位置(带着列宽与冻结):内容与底色都不画,对读屏已隐藏 */
357
+ [data-scope='table']:is([data-part='cell'], [data-part='column-header'])[data-covered] {
358
+ visibility: hidden;
359
+ }
360
+
361
+ /* 高对比档里合并格的底被换成系统底色,盖住行间线这件事照旧成立;补一圈系统描边标出合并区 */
362
+ @media (forced-colors: active) {
363
+ [data-scope='table']:is([data-part='cell'], [data-part='column-header'])[data-row-span] {
364
+ outline: var(--xh-stroke-thin) solid CanvasText;
365
+ outline-offset: calc(-1 * var(--xh-stroke-thin));
366
+ }
367
+ }
368
+ /* 分组表头横跨它的几列,名字居中压在这几列正上方 */
369
+ [data-scope='table'][data-part='column-header'][data-group] {
370
+ justify-content: center;
371
+ }
372
+
314
373
  /* 横向吸附:钉在滚动容器的一侧。背景继承自行,跟着选中/高亮一起变,
315
374
  滚过去时不会露出一块与所在行不同色的补丁。
316
375
  同侧多列时的偏移由连接层按前面各列的宽度累加好写进 --xh-table-sticky-inset */
@@ -334,7 +393,43 @@
334
393
  /* 表头行本身透明(露出表头底),吸附的列头继承到的就是透明——得自己带表头底,
335
394
  否则横向滚动时其它列头从它下面穿过去 */
336
395
  [data-scope='table'][data-part='column-header'][data-frozen] {
337
- background: var(--xh-table-header-bg, var(--xh-bg-subtle));
396
+ background: var(--xh-table-header-bg, var(--xh-bg-subtle-opaque));
397
+ }
398
+
399
+ /* 冻结列的边界:紧挨滚动区的那一列在朝向滚动区的一侧画一道描边,只在确有内容被压住时出现——
400
+ 行首冻结列在滚离起始端之后、行尾冻结列在还没滚到末端时。冻结列与被压住的内容同在一个平面上,
401
+ 层级靠描边而不是阴影;线常驻、按 micro 淡入淡出,不改格子的盒尺寸 */
402
+ [data-scope='table']:is([data-part='column-header'], [data-part='cell'])[data-frozen-edge]::after {
403
+ content: '';
404
+ position: absolute;
405
+ inset-block: 0;
406
+ inline-size: var(--xh-stroke-thin);
407
+ background: var(--xh-table-frozen-edge, var(--xh-border-default));
408
+ opacity: 0;
409
+ pointer-events: none;
410
+ transition: opacity var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
411
+ }
412
+
413
+ [data-scope='table']:is([data-part='column-header'], [data-part='cell'])[data-frozen-edge][data-frozen='start']::after {
414
+ inset-inline-end: 0;
415
+ }
416
+
417
+ [data-scope='table']:is([data-part='column-header'], [data-part='cell'])[data-frozen-edge][data-frozen='end']::after {
418
+ inset-inline-start: 0;
419
+ }
420
+
421
+ /* root 恒报两端(没有冻结列时两端都算贴着);虚拟滚动的行隔着视口,按后代认 */
422
+ [data-scope='table'][data-part='root']:not([data-at-min-horizontal]) :is([data-part='column-header'], [data-part='cell'])[data-frozen-edge][data-frozen='start']::after,
423
+ [data-scope='table'][data-part='root']:not([data-at-max-horizontal]) :is([data-part='column-header'], [data-part='cell'])[data-frozen-edge][data-frozen='end']::after {
424
+ opacity: 1;
425
+ }
426
+
427
+ /* 边界线是一块底色,系统色下会被抹成 Canvas:换成 CanvasText 并只让这条线不参与强制换色 */
428
+ @media (forced-colors: active) {
429
+ [data-scope='table']:is([data-part='column-header'], [data-part='cell'])[data-frozen-edge]::after {
430
+ background: CanvasText;
431
+ forced-color-adjust: none;
432
+ }
338
433
  }
339
434
 
340
435
  /* —— 三个可叠加的外观开关 —— */
@@ -345,7 +440,7 @@
345
440
  :where([data-scope='table'][data-part='root'][data-striped] [data-scope='table'][data-part='body']) > [data-scope='table'][data-part='row']:where(:nth-of-type(even)) {
346
441
  /* 改的是家族的 rest 槽而不是 background 本身:悬停、选中、按下各态由家族在同一支私有槽上解算,
347
442
  直接写 background 会把它们全压掉 */
348
- --xh-collection-bg-rest: var(--xh-table-row-bg-striped, var(--xh-bg-subtle));
443
+ --xh-collection-bg-rest: var(--xh-table-row-bg-striped, var(--xh-bg-subtle-opaque));
349
444
  }
350
445
 
351
446
  /* 形态:outline 画一圈描边加圆角;ghost 即基础规则,只留行间横线,圆角也随之无意义 */
@@ -355,8 +450,9 @@
355
450
  background: var(--xh-table-bg, var(--xh-bg-surface));
356
451
  }
357
452
 
358
- /* 淡底档:不画描边,surface 圆角 + subtle 底 */
453
+ /* 淡底档:描边退成透明占位(不去掉),与 outline 档同盒尺寸,换档不跳 1px;surface 圆角 + subtle 底 */
359
454
  [data-scope='table'][data-part='root'][data-variant='subtle'] {
455
+ border: var(--xh-stroke-thin) solid transparent;
360
456
  border-radius: var(--xh-table-radius, var(--xh-shape-surface));
361
457
  background: var(--xh-table-bg, var(--xh-bg-subtle));
362
458
  }
@@ -400,8 +496,7 @@
400
496
  }
401
497
 
402
498
  /* 家族 icon 档在粗指针下用 ::after 扩热区到 44px:五颗把手密排在行首与列头里(coarse-target 登记的
403
- A 档存量),外扩会与相邻把手和上下行叠上;热区不外扩,全选框的 ::after 又是半选那道横杠、
404
- 排序钮的 ::after 是多列排序的序号角标 */
499
+ A 档存量),外扩会与相邻把手和上下行叠上;热区不外扩,排序钮的 ::after 是多列排序的序号角标 */
405
500
  @media (pointer: coarse) {
406
501
  [data-scope='table'][data-part='select-all-trigger']::after,
407
502
  [data-scope='table'][data-part='row-select-trigger']::after,
@@ -461,8 +556,8 @@
461
556
  display: none;
462
557
  }
463
558
 
464
- /* 三个勾选把手:未选中时只剩一个空框(描边画出的透明底空框),勾选标记靠前景色显隐,
465
- 切换选中不引起行宽抖动 */
559
+ /* 三个勾选把手:未选中时只剩一个空框(描边画出的透明底空框)。框里的勾与半选杠由勾选标记配方画:
560
+ 常驻、按状态淡变并轻缩放,标记色恒为面上的前景,切换选中不引起行宽抖动 */
466
561
  [data-scope='table'][data-part='select-all-trigger'],
467
562
  [data-scope='table'][data-part='row-select-trigger'],
468
563
  [data-scope='table'][data-part='column-visibility-trigger'] {
@@ -480,7 +575,7 @@
480
575
  /* 已勾选的方框是品牌实心面,按下在它之上派生 active 面 */
481
576
  [data-scope='table'][data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate']),
482
577
  [data-scope='table'][data-part='column-visibility-trigger'][data-state='checked'],
483
- [data-scope='table'][data-part='row-select-trigger'][data-selected] {
578
+ [data-scope='table'][data-part='row-select-trigger']:is([data-selected], [data-indeterminate]) {
484
579
  --xh-_table-trigger-bg: var(--xh-table-trigger-bg-checked, var(--xh-bg-brand));
485
580
  --xh-_table-trigger-bg-pressed: var(--xh-table-trigger-bg-checked-pressed, var(--xh-bg-brand-active));
486
581
  --xh-_table-trigger-border: var(--xh-table-trigger-border-checked, var(--xh-table-trigger-bg-checked, var(--xh-bg-brand)));
@@ -488,50 +583,21 @@
488
583
 
489
584
  /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
490
585
  那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的。
491
- 置灰那档不在其列:底已换成淡底、勾也藏成透明,currentColor 取到的是透明,环整个消失;
492
- aria-disabled 的把手仍能落焦,环退回默认那一支 */
586
+ 置灰那档不在其列:底已换成淡底,aria-disabled 的把手仍能落焦,环退回默认那一支 */
493
587
  [data-scope='table'][data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate']):not([data-disabled]),
494
588
  [data-scope='table'][data-part='column-visibility-trigger'][data-state='checked']:not([data-disabled]),
495
- [data-scope='table'][data-part='row-select-trigger'][data-selected]:not([data-disabled]) {
589
+ [data-scope='table'][data-part='row-select-trigger']:is([data-selected], [data-indeterminate]):not([data-disabled]) {
496
590
  --xh-action-ring-color-focus-visible: currentColor;
497
591
  }
498
592
 
499
- /* 半选档的前景是透明的(勾藏起来、横杠由伪元素画),currentColor 取到的是透明;
500
- 环直接取面配对的那支前景色 */
501
- [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate']:not([data-disabled]) {
502
- --xh-action-ring-color-focus-visible: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
503
- }
504
-
505
- /* 未选中时勾不出现,但盒子还在:它是边框画出来的空框 */
506
- [data-scope='table'][data-part='select-all-trigger'][data-state='unchecked'],
507
- [data-scope='table'][data-part='column-visibility-trigger'][data-state='unchecked'],
508
- [data-scope='table'][data-part='row-select-trigger']:not([data-selected]) {
509
- --xh-_table-trigger-fg: transparent;
510
- }
511
-
512
- /* 半选换一枚横杠字形盖住勾:aria-checked=mixed 在视觉上也得与"全选"分得开。
513
- 横杠与勾同走字形令牌,作者换掉标记时两态一起换 */
514
- [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate'] {
515
- --xh-_table-trigger-fg: transparent;
516
- }
517
-
518
- [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate']::after {
519
- position: absolute;
520
- inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
521
- block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
522
- background-color: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
523
- content: '';
524
- -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
525
- mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
526
- }
527
-
528
- /* 禁用:--xh-border-default 描边 + --xh-bg-subtle 底,勾藏起来;家族的禁用块按映射给 */
593
+ /* 禁用:--xh-border-default 描边 + --xh-bg-subtle 底 + --xh-fg-disabled 勾,与独立 Checkbox 同一档;
594
+ 家族的禁用块按映射给 */
529
595
  [data-scope='table'][data-part='select-all-trigger'][data-disabled],
530
596
  [data-scope='table'][data-part='column-visibility-trigger'][data-disabled],
531
597
  [data-scope='table'][data-part='row-select-trigger'][data-disabled] {
532
598
  --xh-action-border-disabled: var(--xh-border-default);
533
599
  --xh-action-bg-disabled: var(--xh-bg-subtle);
534
- --xh-action-fg-disabled: transparent;
600
+ --xh-action-fg-disabled: var(--xh-fg-disabled);
535
601
  }
536
602
 
537
603
  /* 行选择把手不占 Tab 位(键盘那一路走 Space),只服务指针 */
@@ -550,7 +616,7 @@
550
616
 
551
617
  /* 这条整份改写家族的过渡列表,按压的 scale 与换底要一起带回来 */
552
618
  transition:
553
- rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter-strong),
619
+ rotate var(--xh-motion-duration-nudge) var(--xh-motion-ease-enter-strong),
554
620
  background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
555
621
  scale var(--xh-motion-duration-release) var(--xh-motion-ease-release);
556
622
  }
@@ -847,7 +913,7 @@
847
913
  禁用的行不接换父落点,:not([data-disabled]) 不会漏画任何一处高亮 */
848
914
  [data-scope='table'][data-part='root'] [data-scope='table'][data-part='body'] > [data-scope='table'][data-part='row'][data-drop='inside']:not([data-disabled]) {
849
915
  /* 落点不是选中:品牌淡底专属选中,落点面取悬停之上一档的中性面 */
850
- background: var(--xh-table-drop-inside-bg, var(--xh-bg-subtle-hover));
916
+ background: var(--xh-table-drop-inside-bg, var(--xh-bg-subtle-hover-opaque));
851
917
  }
852
918
 
853
919
  /* 换父那一档的描边:与底色分两层画,因为它得压在横向吸附的格子之上——
@@ -940,11 +1006,13 @@
940
1006
  content: none;
941
1007
  }
942
1008
 
943
- /* 详情行:靠 data-state 收起,不卸载作者节点。内容长在它的单元格里,行本身只画底色 */
1009
+ /* 详情行:靠 data-state 收起,不卸载作者节点。内容长在它的单元格里,行本身只画底色;
1010
+ 换位时随它的数据行一起从旧位置滑到新位置 */
944
1011
  [data-scope='table'][data-part='expanded-row'] {
945
1012
  display: flex;
946
1013
  align-items: stretch;
947
1014
  background: var(--xh-table-detail-bg, var(--xh-bg-subtle));
1015
+ transition: translate var(--xh-motion-duration-move) var(--xh-motion-ease-continuous);
948
1016
  }
949
1017
 
950
1018
  /* 详情行里的格子铺满整行,且不按数据格那样截断成一行 */
@@ -962,17 +1030,17 @@
962
1030
  display: none;
963
1031
  }
964
1032
 
965
- /* 两个状态节点常挂,只在表体为空时才显形 */
1033
+ /* 两个占位节点常挂,只在表体为空时才显形,占同一个位置、同一副排版:一行文案居中,字号随表格的尺寸档
1034
+ (从 root 继承),次要文字色,块向内距一档、行内与单元格文字对齐,不设最小高——占位不撑出空白 */
966
1035
  [data-scope='table'][data-part='empty'],
967
1036
  [data-scope='table'][data-part='loading'] {
968
1037
  display: flex;
969
- flex-direction: column;
970
1038
  align-items: center;
971
1039
  justify-content: center;
972
- gap: var(--xh-table-state-gap, var(--xh-space-2));
973
- min-block-size: var(--xh-table-state-min-h, 8rem);
974
- padding-block: var(--xh-table-state-py, var(--xh-space-6));
975
- padding-inline: var(--xh-table-state-px, var(--xh-space-4));
1040
+ gap: var(--xh-table-state-gap, var(--xh-control-gap-md));
1041
+ min-block-size: var(--xh-table-state-min-h, 0);
1042
+ padding-block: var(--xh-table-state-py, var(--xh-space-3));
1043
+ padding-inline: var(--xh-table-state-px, var(--xh-control-px-sm));
976
1044
  color: var(--xh-table-state-fg, var(--xh-fg-muted));
977
1045
  text-align: center;
978
1046
  }
@@ -982,9 +1050,14 @@
982
1050
  display: none;
983
1051
  }
984
1052
 
985
- [data-scope='table'][data-part='loading'] {
986
- animation: xh-table-loading-pulse var(--xh-table-loading-duration, var(--xh-shimmer-duration))
987
- var(--xh-motion-ease-sweep) infinite;
1053
+ /* 还没有行、正在取:一枚加载环排在文案之前。环由加载环配方画成(轨道 + 起始边、随 data-loading 淡入并转),
1054
+ 这里只给它盒子:直径取表格尺寸档的图标档;转一圈的时长走公开槽 */
1055
+ [data-scope='table'][data-part='loading']::before {
1056
+ content: '';
1057
+ flex: none;
1058
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-md));
1059
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-md));
1060
+ animation-duration: var(--xh-table-loading-duration, var(--xh-motion-loop-spin));
988
1061
  }
989
1062
 
990
1063
  /* 取下一页的按钮:铺满一行摆在表尾——铺满一行的独立动作条目,接 Action Control 的 row 档、
@@ -1012,33 +1085,9 @@
1012
1085
  display: none;
1013
1086
  }
1014
1087
 
1015
- /* 减少动效:呼吸停下,加载态只留静止的文案。两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
1016
- @media (prefers-reduced-motion: reduce) {
1017
- [data-scope='table'][data-part='loading'] {
1018
- animation: none;
1019
- }
1020
- }
1021
-
1022
- :where([data-motion='reduce']) [data-scope='table'][data-part='loading'] {
1023
- animation: none;
1024
- }
1025
-
1026
- /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中。
1027
- 尺寸读把手自己改接过的 --xh-icon-size:勾是方盒边长 × 0.75、chevron 与方盒同边长(见把手块) */
1028
- [data-scope='table'][data-part='select-all-trigger']:empty::before,
1029
- [data-scope='table'][data-part='column-visibility-trigger']:empty::before,
1030
- [data-scope='table'][data-part='row-select-trigger']:empty::before {
1031
- content: '';
1032
- display: inline-block;
1033
- inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
1034
- block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
1035
- vertical-align: var(--xh-glyph-baseline-shift);
1036
- background-color: currentColor;
1037
- -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
1038
- mask: var(--xh-glyph-mark-check) center / contain no-repeat;
1039
- }
1040
-
1041
- /* flex: none:方盒是 ghost 形态,家族那圈透明描边仍占位,不钉住的话与盒同边长的 chevron 会被挤窄一个描边 */
1088
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这条即不命中。三颗勾选框里的勾由勾选标记配方画;
1089
+ 尺寸读把手自己改接过的 --xh-icon-size:chevron 与方盒同边长(见把手块)。
1090
+ flex: none:方盒是 ghost 形态,家族那圈透明描边仍占位,不钉住的话与盒同边长的 chevron 会被挤窄一个描边 */
1042
1091
  [data-scope='table'][data-part='expand-trigger']:empty::before {
1043
1092
  content: '';
1044
1093
  display: inline-block;
@@ -1052,13 +1101,7 @@
1052
1101
  }
1053
1102
 
1054
1103
  @media print {
1055
- /* 打印:动画会被定格在任意一帧——转了一半的圈、扫到一半的微光。这里换成静止的表达,
1056
- 取值与减弱动效那一档相同。两档各写一块、不并进一条媒体查询列表:减弱动效另有一份
1057
- :where([data-motion='reduce']) 的钩子版本与它成对,打印没有对应的钩子可配,
1058
- 并成一条之后这层配对关系在文本上就断了。 */
1059
- [data-scope='table'][data-part='loading'] {
1060
- animation: none;
1061
- }
1104
+ /* 加载环的静止替代(点线环)由加载环配方给,减弱动效与打印同一档 */
1062
1105
 
1063
1106
  /* 底色被丢掉:选中行那层淡底没了,与别的行一模一样。改画一条内收的实线框——
1064
1107
  用 outline 不用 border:行是横排 flex,加边会把单元格整体往里推,没选中的行不加边,
@@ -1071,18 +1114,32 @@
1071
1114
  /* 两个勾选框的实心底也被丢掉,配它的浅色勾落在白纸上就整个不见了——
1072
1115
  勾与框都换成正文色,勾没勾在纸上才分得出 */
1073
1116
  [data-scope='table'][data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate']),
1074
- [data-scope='table'][data-part='row-select-trigger'][data-selected] {
1117
+ [data-scope='table'][data-part='row-select-trigger']:is([data-selected], [data-indeterminate]) {
1075
1118
  border-color: var(--xh-fg-default);
1076
1119
  }
1077
1120
 
1078
- [data-scope='table'][data-part='select-all-trigger'][data-state='checked'],
1079
- [data-scope='table'][data-part='row-select-trigger'][data-selected] {
1121
+ [data-scope='table'][data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate']),
1122
+ [data-scope='table'][data-part='row-select-trigger']:is([data-selected], [data-indeterminate]) {
1080
1123
  color: var(--xh-fg-default);
1081
1124
  }
1125
+ }
1126
+
1127
+ @media (forced-colors: active) {
1128
+ /* 兜底字形是 mask 挖出来的一块底色,这一档里底色被系统换成 Canvas,字形跟着消失。
1129
+ 字形退出强制换色、直接写系统色(不能取 currentColor:退出强制换色的伪元素读到的是被系统换掉之前的作者色):
1130
+ 按钮面上取 ButtonText,悬停与按下时家族把按钮涂成 Highlight、字形换 HighlightText;
1131
+ 禁用取 GrayText */
1132
+ [data-scope='table']:is([data-part='sort-trigger'], [data-part='expand-trigger']):empty::before {
1133
+ forced-color-adjust: none;
1134
+ background-color: ButtonText;
1135
+ }
1136
+
1137
+ [data-scope='table']:is([data-part='sort-trigger'], [data-part='expand-trigger']):not([data-disabled]):not([data-loading]):is(:hover, :active, [data-pressed]):empty::before {
1138
+ background-color: HighlightText;
1139
+ }
1082
1140
 
1083
- /* 半选那枚横杠是伪元素画的,字色照旧留成透明把勾压住,只换横杠自己的颜色 */
1084
- [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate']::after {
1085
- background-color: var(--xh-fg-default);
1141
+ [data-scope='table']:is([data-part='sort-trigger'], [data-part='expand-trigger'])[data-disabled]:empty::before {
1142
+ background-color: GrayText;
1086
1143
  }
1087
1144
  }
1088
1145
  }