@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
package/css/table.css CHANGED
@@ -1,11 +1,23 @@
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
+ /* 定义 table 样式。 */
7
+
8
+ @import '../family/action-control.css';
9
+ @import '../family/collection-item.css';
10
+
1
11
  @layer xihan.motion {
2
12
  /* 加载态自己冒出来,用户没按任何键:一段极轻的呼吸就够,别抢走正在读表的注意力 */
13
+ /* 一次呼吸自带来回:起止两端与中点各写一帧,声明的周期就是一次完整的明暗往返 */
3
14
  @keyframes xh-table-loading-pulse {
4
- from {
15
+ 0%,
16
+ 100% {
5
17
  opacity: var(--xh-state-disabled-opacity);
6
18
  }
7
19
 
8
- to {
20
+ 50% {
9
21
  opacity: 1;
10
22
  }
11
23
  }
@@ -23,8 +35,10 @@
23
35
  既不让页面上的层号插进来,也不让它们漏出去压住别人 */
24
36
  isolation: isolate;
25
37
 
26
- /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
27
- --xh-icon-size: var(--xh-table-icon-size, var(--xh-glyph-size-text));
38
+ /* 作者放进单元格、列头与把手里的图标按档取尺,缺省 md(§6.5);表体行上的由家族随 data-xh-collection-size 下发。
39
+ 表格自绘的状态字形(排序方向、勾、半选杠、展开方向)不读这支:它们是指示符,与所在的方盒同走
40
+ --xh-control-indicator-* 一族——五颗把手在自己身上把 --xh-icon-size 改接到方盒的尺,排序钮那支叫 --xh-table-sort-size */
41
+ --xh-icon-size: var(--xh-table-icon-size, var(--xh-glyph-size-md));
28
42
 
29
43
  /* 密度档只换这两个私有槽:单元格与列标题从 root 继承前者,字号靠 font-size 本身继承下去,
30
44
  换档不必给每个部件各写一条选择器,列宽那套算法也一点不碰 */
@@ -34,9 +48,13 @@
34
48
  display: flex;
35
49
  position: relative;
36
50
  flex-direction: column;
37
- max-block-size: var(--xh-table-max-h, var(--xh-viewport-h-lg));
38
- border: var(--xh-stroke-thin) solid var(--xh-table-border, var(--xh-border-default));
39
- border-radius: var(--xh-table-radius, var(--xh-shape-surface));
51
+ /* 高度上限再由视口收一次:定值比屏幕还高时表格自己滚不动,只能靠页面滚,
52
+ 吸顶表头也就钉不住。视口取 dvb:移动端地址栏收放会改变可视高度,dvb 跟着变;
53
+ 不认 dvb 的引擎由级联回落到前一条的 vh */
54
+ max-block-size: min(var(--xh-table-max-h, var(--xh-viewport-h-lg)), 100vh);
55
+ max-block-size: min(var(--xh-table-max-h, var(--xh-viewport-h-lg)), 100dvb);
56
+ /* 外框由 [data-variant='outline'] 画;ghost 不画外框,只留行间横线 */
57
+ border: 0;
40
58
  background: var(--xh-table-bg, var(--xh-bg-surface));
41
59
  color: var(--xh-table-fg, var(--xh-fg-default));
42
60
  font-size: var(--xh-table-font-size, var(--xh-_table-font-size));
@@ -65,11 +83,13 @@
65
83
  /* —— 密度 —— */
66
84
  /* 中间档不写规则,缺省即中档 */
67
85
  [data-scope='table'][data-part='root'][data-size='sm'] {
86
+ --xh-icon-size: var(--xh-table-icon-size, var(--xh-glyph-size-sm));
68
87
  --xh-_table-cell-py: var(--xh-table-cell-py-sm);
69
88
  --xh-_table-font-size: var(--xh-control-font-sm);
70
89
  }
71
90
 
72
91
  [data-scope='table'][data-part='root'][data-size='lg'] {
92
+ --xh-icon-size: var(--xh-table-icon-size, var(--xh-glyph-size-lg));
73
93
  --xh-_table-cell-py: var(--xh-table-cell-py-lg);
74
94
  --xh-_table-font-size: var(--xh-control-font-lg);
75
95
  }
@@ -88,6 +108,56 @@
88
108
  display: none;
89
109
  }
90
110
 
111
+ /* —— 工具条与列设置区 —— */
112
+ /* 两块都摆在 root 之外:root 是 grid 系角色,子节点只能是 row 与 rowgroup。
113
+ 工具条只管排布,里头控件的观感归控件自己的皮肤 */
114
+ [data-scope='table'][data-part='toolbar'] {
115
+ /* 尺寸档只换这一个私有槽:控件之间的间距 */
116
+ --xh-_table-toolbar-gap: var(--xh-space-2);
117
+
118
+ display: flex;
119
+ flex-wrap: wrap;
120
+ align-items: center;
121
+ gap: var(--xh-table-toolbar-gap, var(--xh-_table-toolbar-gap));
122
+ padding-block: var(--xh-table-toolbar-py, var(--xh-space-2));
123
+ color: var(--xh-table-toolbar-fg, var(--xh-fg-default));
124
+ }
125
+
126
+ [data-scope='table'][data-part='toolbar'][data-size='sm'] {
127
+ --xh-_table-toolbar-gap: var(--xh-space-1);
128
+ }
129
+
130
+ [data-scope='table'][data-part='toolbar'][data-size='lg'] {
131
+ --xh-_table-toolbar-gap: var(--xh-space-3);
132
+ }
133
+
134
+ [data-scope='table'][data-part='toolbar'][hidden] {
135
+ display: none;
136
+ }
137
+
138
+ /* 列设置区:一列一行竖着排。它常摆在浮层里,宽高都交给外面那层容器定 */
139
+ [data-scope='table'][data-part='column-list'] {
140
+ --xh-_table-column-list-gap: var(--xh-space-1);
141
+
142
+ display: flex;
143
+ flex-direction: column;
144
+ gap: var(--xh-table-column-list-gap, var(--xh-_table-column-list-gap));
145
+ color: var(--xh-table-column-list-fg, var(--xh-fg-default));
146
+ font-size: var(--xh-table-column-list-font-size, var(--xh-text-secondary-size));
147
+ }
148
+
149
+ [data-scope='table'][data-part='column-list'][data-size='sm'] {
150
+ --xh-_table-column-list-gap: var(--xh-space-0_5);
151
+ }
152
+
153
+ [data-scope='table'][data-part='column-list'][data-size='lg'] {
154
+ --xh-_table-column-list-gap: var(--xh-space-2);
155
+ }
156
+
157
+ [data-scope='table'][data-part='column-list'][hidden] {
158
+ display: none;
159
+ }
160
+
91
161
  /* 三个区段都是竖着排行的块。min-inline-size: max-content 让它们跟着最宽的一行一起横向溢出,
92
162
  否则横向滚动时右半边的行会在容器边缘被切断 */
93
163
  [data-scope='table'][data-part='header'],
@@ -109,14 +179,19 @@
109
179
  outline: none;
110
180
  }
111
181
 
182
+ /* 表头是淡底承载面:里头的触发器按淡底阶梯走(hover 200 → pressed 300),阶梯由 host 槽向内下发(§7.2);
183
+ 排序钮是 ghost 图标钮,悬停 / 按下面就从这两支 host 槽取 */
112
184
  [data-scope='table'][data-part='header'] {
185
+ --xh-action-host-bg-hover: var(--xh-bg-subtle-hover);
186
+ --xh-action-host-bg-pressed: var(--xh-bg-subtle-active);
187
+
113
188
  border-block-end: var(--xh-stroke-thin) solid var(--xh-table-border, var(--xh-border-default));
114
189
  background: var(--xh-table-header-bg, var(--xh-bg-subtle));
115
190
  }
116
191
 
117
192
  /* 吸顶:滚动容器是 root,表头钉在它的上沿。背景必须是实色——
118
193
  透明的表头会让底下滚过的行透出来 */
119
- [data-scope='table'][data-part='header'][data-sticky] {
194
+ [data-scope='table'][data-part='header'][data-fixed] {
120
195
  position: sticky;
121
196
  z-index: var(--xh-table-sticky-header-layer, var(--xh-layer-sticky));
122
197
  inset-block-start: 0;
@@ -128,48 +203,72 @@
128
203
  font-weight: var(--xh-table-footer-font-weight, var(--xh-font-weight-medium));
129
204
  }
130
205
 
206
+ /* 表体行走 Collection Item 的 page 语境(页内持久集合,§7.3):悬停 / 高亮 / 按下面(白底承载 hover 100 →
207
+ pressed 200)与选中面(品牌淡底 + 淡底前景,selected+hover 20% / +pressed 28%)由家族按 aria-selected /
208
+ aria-disabled 给出,标记由行首的勾选把手承担。这里只把公开槽映射到桥接槽,并逐项盖掉家族的行盒几何:
209
+ 行是 flex 容器(列宽由单元格的内联尺寸决定,不进家族网格)、不内衬、不圆角、字号与光标随表格本身
210
+ (行不是按钮,selectable 与否都不改光标)。表头 / 脚注行不投影家族,只共用这一副 flex 盒 */
131
211
  [data-scope='table'][data-part='row'] {
212
+ /* rest 底要实色:横向吸附的单元格靠 inherit 取它,透明会让滚过的内容透出来 */
213
+ --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));
217
+ --xh-collection-bg-selected: var(--xh-table-row-bg-selected, var(--xh-bg-brand-subtle));
218
+ --xh-collection-fg-rest: currentColor;
219
+ --xh-collection-fg-hover: currentColor;
220
+ --xh-collection-fg-keyboard-highlight: currentColor;
221
+ --xh-collection-fg-pressed: currentColor;
222
+ --xh-collection-fg-selected: var(--xh-table-row-fg-selected, var(--xh-fg-on-brand-subtle));
223
+ --xh-collection-fg-selected-hover: var(--xh-table-row-fg-selected, var(--xh-fg-on-brand-subtle));
224
+ --xh-collection-fg-selected-highlight: var(--xh-table-row-fg-selected, var(--xh-fg-on-brand-subtle));
225
+ --xh-collection-fg-selected-pressed: var(--xh-table-row-fg-selected, var(--xh-fg-on-brand-subtle));
226
+ --xh-collection-font-size: var(--xh-table-font-size, var(--xh-_table-font-size));
227
+ --xh-collection-cursor-rest: var(--xh-table-row-cursor, default);
228
+ --xh-collection-cursor-hover: var(--xh-table-row-cursor, default);
229
+ --xh-collection-cursor-keyboard-highlight: var(--xh-table-row-cursor, default);
230
+ --xh-collection-cursor-pressed: var(--xh-table-row-cursor, default);
231
+ --xh-collection-cursor-selected: var(--xh-table-row-cursor, default);
232
+ --xh-collection-cursor-selected-hover: var(--xh-table-row-cursor, default);
233
+ --xh-collection-cursor-selected-highlight: var(--xh-table-row-cursor, default);
234
+ --xh-collection-cursor-selected-pressed: var(--xh-table-row-cursor, default);
235
+ --xh-collection-cursor-disabled: var(--xh-table-row-cursor, default);
236
+ /* data-highlighted 跟的是连接层记的焦点行(指针点选也会落焦):只换面,焦点环在 :focus-visible 下再接回 */
237
+ --xh-collection-outline-keyboard-highlight: transparent;
238
+ --xh-collection-outline-selected-highlight: transparent;
239
+
132
240
  display: flex;
133
241
  align-items: stretch;
134
- /* 背景要实色:横向吸附的单元格靠 inherit 取它,透明会让滚过的内容透出来 */
135
- background: var(--xh-table-row-bg, var(--xh-bg-surface));
242
+ padding: 0;
243
+ border-radius: 0;
244
+ /* 文字度量归单元格,行不给行高 */
245
+ line-height: inherit;
136
246
  }
137
247
 
248
+ /* 家族给了 display,UA 的 [hidden]{display:none} 已被盖掉 */
138
249
  [data-scope='table'][data-part='row'][hidden] {
139
250
  display: none;
140
251
  }
141
252
 
253
+ /* 表头 / 脚注行透明,露出区段容器的淡底 */
142
254
  [data-scope='table'][data-part='header'] > [data-scope='table'][data-part='row'],
143
255
  [data-scope='table'][data-part='footer'] > [data-scope='table'][data-part='row'] {
144
256
  background: transparent;
145
257
  }
146
258
 
147
- /* 行间线画在后一行的上沿,区段里第一个可见行不画:行只负责行与行之间,外边界归 root 与区段容器 */
148
- [data-scope='table']:is([data-part='header'], [data-part='body'], [data-part='footer']) > :not([hidden]) ~ [data-scope='table']:is([data-part='row'], [data-part='expanded-row']) {
149
- border-block-start: var(--xh-stroke-thin) solid var(--xh-table-row-border, var(--xh-border-subtle));
150
- }
259
+ /* 键盘焦点出现时环才接回并立即到位,不压在背景过渡的中间帧上;选中行的淡底不是实心面,环走默认色 */
260
+ [data-scope='table'][data-part='row']:focus-visible:not(:hover) {
261
+ --xh-collection-outline-keyboard-highlight: var(--xh-ring-focus);
262
+ --xh-collection-outline-selected-highlight: var(--xh-ring-focus);
151
263
 
152
- /* 悬停与键盘锚点共用中性灰轻档。data-highlighted 跟的是连接层记的焦点行,
153
- 与选中互相独立:可以停在一个没被选中的行上 */
154
- [data-scope='table'][data-part='body'] > [data-scope='table'][data-part='row']:not([data-disabled]):is(:hover, [data-highlighted]) {
155
- background: var(--xh-table-row-bg-hover, var(--xh-bg-subtle));
264
+ transition: none;
156
265
  }
157
266
 
158
- /* 选中比高亮更"实":它表达的是数据状态,翻页回来还在 */
159
- [data-scope='table'][data-part='row'][data-selected] {
160
- background: var(--xh-table-row-bg-selected, var(--xh-bg-subtle-active));
161
- }
162
-
163
- [data-scope='table'][data-part='row'][data-disabled] {
164
- color: var(--xh-fg-disabled);
267
+ /* 行间线画在后一行的上沿,区段里第一个可见行不画:行只负责行与行之间,外边界归 root 与区段容器 */
268
+ [data-scope='table']:is([data-part='header'], [data-part='body'], [data-part='footer']) > :not([hidden]) ~ [data-scope='table']:is([data-part='row'], [data-part='expanded-row']) {
269
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-table-row-border, var(--xh-border-subtle));
165
270
  }
166
271
 
167
- /* 行才是 Tab 停靠点,环画在整行上 */
168
- [data-scope='table'][data-part='row']:focus-visible {
169
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
170
- /* 往内收:行是撑满宽度的,环画在外沿会被滚动容器裁掉 */
171
- outline-offset: calc(-1 * var(--xh-ring-width));
172
- }
173
272
 
174
273
  /* 列宽由连接层写进内联 inline-size,因此 flex-basis 取 auto:
175
274
  写成 0 会把那条内联值整个盖掉,作者给的列宽就此失效 */
@@ -199,6 +298,19 @@
199
298
  user-select: none;
200
299
  }
201
300
 
301
+ /* 列名是列头里唯一可收窄的一格:flex: 1 吃掉余量、把排序钮 / 列宽把手推到行尾,min-inline-size: 0 让它在
302
+ 窄列上收得下去并出省略号。列名不能裸写成文本节点:flex 行里的裸文本是匿名 flex item,min-inline-size 取 auto
303
+ (nowrap 文本的 min-content)缩不下去,96px 的列配一串长列名时定尺的把手连同 auto 外边距一起被挤出列头盒、
304
+ 被列头的 overflow: hidden 裁掉——皮肤给不了匿名项 min-inline-size: 0 与 text-overflow,只有真实节点接得住。
305
+ white-space 与行高照旧从列头继承 */
306
+ [data-scope='table'][data-part='column-label'] {
307
+ flex: 1;
308
+ min-inline-size: 0;
309
+ overflow: hidden;
310
+ text-overflow: ellipsis;
311
+ white-space: nowrap;
312
+ }
313
+
202
314
  /* 横向吸附:钉在滚动容器的一侧。背景继承自行,跟着选中/高亮一起变,
203
315
  滚过去时不会露出一块与所在行不同色的补丁。
204
316
  同侧多列时的偏移由连接层按前面各列的宽度累加好写进 --xh-table-sticky-inset */
@@ -226,20 +338,32 @@
226
338
  }
227
339
 
228
340
  /* —— 三个可叠加的外观开关 —— */
229
- /* 斑马纹:表体偶数行换一层浅底;悬停与选中的底色仍按原规则盖过它 */
230
- [data-scope='table'][data-part='root'][data-striped] [data-scope='table'][data-part='body'] > [data-scope='table'][data-part='row']:nth-of-type(even) {
231
- background: var(--xh-table-row-bg-striped, var(--xh-bg-subtle));
341
+ /* 斑马纹:表体偶数行换一层浅底。它是最底下那一档,悬停、选中、落点都要盖得过它,
342
+ 所以祖先链与 :nth-of-type 都收进 :where()——特指度落到与基础底同档(0-2-0),
343
+ 只靠排在基础底之后压过它一条。照字面写祖先链是 0-8-0,比悬停与选中都高,
344
+ 斑马表里偶数行会既不响应悬停也显不出选中 */
345
+ :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
+ /* 改的是家族的 rest 槽而不是 background 本身:悬停、选中、按下各态由家族在同一支私有槽上解算,
347
+ 直接写 background 会把它们全压掉 */
348
+ --xh-collection-bg-rest: var(--xh-table-row-bg-striped, var(--xh-bg-subtle));
349
+ }
350
+
351
+ /* 形态:outline 画一圈描边加圆角;ghost 即基础规则,只留行间横线,圆角也随之无意义 */
352
+ [data-scope='table'][data-part='root'][data-variant='outline'] {
353
+ border: var(--xh-stroke-thin) solid var(--xh-table-border, var(--xh-border-default));
354
+ border-radius: var(--xh-table-radius, var(--xh-shape-surface));
355
+ background: var(--xh-table-bg, var(--xh-bg-surface));
232
356
  }
233
357
 
234
- /* 无外框:只留行间横线,圆角也随之无意义 */
235
- [data-scope='table'][data-part='root'][data-borderless] {
236
- border: 0;
237
- border-radius: 0;
358
+ /* 淡底档:不画描边,surface 圆角 + subtle 底 */
359
+ [data-scope='table'][data-part='root'][data-variant='subtle'] {
360
+ border-radius: var(--xh-table-radius, var(--xh-shape-surface));
361
+ background: var(--xh-table-bg, var(--xh-bg-subtle));
238
362
  }
239
363
 
240
364
  /* 竖分隔线:列与列之间一道细线,末列不画 */
241
- [data-scope='table'][data-part='root'][data-ruled] [data-scope='table'][data-part='column-header']:not(:last-child),
242
- [data-scope='table'][data-part='root'][data-ruled] [data-scope='table'][data-part='cell']:not(:last-child) {
365
+ [data-scope='table'][data-part='root'][data-split] [data-scope='table'][data-part='column-header']:not(:last-child),
366
+ [data-scope='table'][data-part='root'][data-split] [data-scope='table'][data-part='cell']:not(:last-child) {
243
367
  border-inline-end: var(--xh-stroke-thin) solid var(--xh-table-row-border, var(--xh-border-subtle));
244
368
  }
245
369
 
@@ -247,52 +371,148 @@
247
371
  color: var(--xh-fg-disabled);
248
372
  }
249
373
 
250
- /* 三个把手共用一副方形盒子,两种行的文字起点才对得齐 */
374
+ /* 五个把手共用一副方形盒子,两种行的文字起点才对得齐;列设置区那颗与表头里的选择框同款,一眼看得出是同一件事。
375
+ 五颗都接 Action Control icon 档(§9.1 定尺方框):盒型、悬停 / 按下 / 禁用面、0.97 缩放与换底、焦点环与过渡由家族
376
+ 配方给,这里只把使用者槽映射到桥接槽;边长仍按 --xh-control-indicator-size 走。三颗勾选框是 outline 形态
377
+ (字段静息形态:透明底 + --xh-border-control 描边),展开箭头与排序钮是 ghost;空框与箭头坐在白底行上,
378
+ 按下落 200 档,已勾选的品牌实心面按下派生 active 面;排序钮坐在表头淡底上,阶梯另由 host 槽给(见下) */
379
+ [data-scope='table'][data-part='select-all-trigger'],
380
+ [data-scope='table'][data-part='row-select-trigger'],
381
+ [data-scope='table'][data-part='column-visibility-trigger'],
382
+ [data-scope='table'][data-part='expand-trigger'],
383
+ [data-scope='table'][data-part='sort-trigger'] {
384
+ --xh-_table-trigger-bg: transparent;
385
+ --xh-_table-trigger-bg-pressed: var(--xh-table-trigger-bg-pressed, var(--xh-bg-subtle-hover));
386
+ --xh-_table-trigger-border: transparent;
387
+ /* 方盒边长:四颗把手与盒里的字形都从这一支取 */
388
+ --xh-_table-trigger-size: var(--xh-table-trigger-size, var(--xh-control-indicator-size));
389
+
390
+ --xh-action-visual-size: var(--xh-_table-trigger-size);
391
+ --xh-action-min-inline-size: var(--xh-_table-trigger-size);
392
+ --xh-action-bg-rest: var(--xh-_table-trigger-bg);
393
+ --xh-action-bg-hover: var(--xh-_table-trigger-bg);
394
+ --xh-action-bg-pressed: var(--xh-_table-trigger-bg-pressed);
395
+ --xh-action-bg-focus-visible: var(--xh-_table-trigger-bg);
396
+ --xh-action-border-rest: var(--xh-_table-trigger-border);
397
+ --xh-action-border-hover: var(--xh-_table-trigger-border);
398
+ --xh-action-border-pressed: var(--xh-_table-trigger-border);
399
+ --xh-action-border-focus-visible: var(--xh-_table-trigger-border);
400
+ }
401
+
402
+ /* 家族 icon 档在粗指针下用 ::after 扩热区到 44px:五颗把手密排在行首与列头里(coarse-target 登记的
403
+ A 档存量),外扩会与相邻把手和上下行叠上;热区不外扩,全选框的 ::after 又是半选那道横杠、
404
+ 排序钮的 ::after 是多列排序的序号角标 */
405
+ @media (pointer: coarse) {
406
+ [data-scope='table'][data-part='select-all-trigger']::after,
407
+ [data-scope='table'][data-part='row-select-trigger']::after,
408
+ [data-scope='table'][data-part='column-visibility-trigger']::after,
409
+ [data-scope='table'][data-part='expand-trigger']::after,
410
+ [data-scope='table'][data-part='sort-trigger']::after {
411
+ min-inline-size: 0;
412
+ min-block-size: 0;
413
+ }
414
+
415
+ /* 序号角标要保住自己的字盒:家族热区那条把伪元素撑成盒的 100%,这里退回内容尺寸;落点与位移由基础规则给。
416
+ 行首起点也要交还:家族热区写了 inset-inline-start: 50%,基础规则只钉了 inset-inline-end: 0,两头都定的
417
+ 绝对定位盒被过约束成方盒的一半(16px 盒里只剩 8px),两位数序号会被截断 */
418
+ [data-scope='table'][data-part='sort-trigger'][data-sort-index]::after {
419
+ inline-size: auto;
420
+ block-size: auto;
421
+ inset-inline-start: auto;
422
+ }
423
+ }
424
+
425
+ /* 盒里的字形是指示符(§6.5):这四颗把手各自把 --xh-icon-size 改接到方盒的尺上,兜底字形与作者塞进盒里的
426
+ XhIcon 读同一把尺,root 那支只管作者放进单元格与把手里图标的 --xh-table-icon-size 不流进来。
427
+ 三颗勾选框的勾与半选杠按方盒边长 × 0.75,与 Checkbox 的 --xh-_checkbox-glyph、Tree 勾选把手同一比例;
428
+ 展开箭头的 chevron 与方盒同边长,同 Tree 的 branch-trigger */
251
429
  [data-scope='table'][data-part='select-all-trigger'],
252
430
  [data-scope='table'][data-part='row-select-trigger'],
431
+ [data-scope='table'][data-part='column-visibility-trigger'] {
432
+ --xh-icon-size: calc(var(--xh-_table-trigger-size) * 0.75);
433
+ }
434
+
253
435
  [data-scope='table'][data-part='expand-trigger'] {
254
- display: inline-flex;
255
- flex: none;
256
- align-items: center;
257
- justify-content: center;
258
- inline-size: var(--xh-table-trigger-size, var(--xh-control-indicator-size));
259
- block-size: var(--xh-table-trigger-size, var(--xh-control-indicator-size));
260
- border-radius: var(--xh-table-trigger-radius, var(--xh-shape-control));
261
- cursor: pointer;
436
+ --xh-icon-size: var(--xh-_table-trigger-size);
437
+ }
438
+
439
+ /* 排序箭头留一支自己的公开槽,缺省与方盒同边长 */
440
+ [data-scope='table'][data-part='sort-trigger'] {
441
+ --xh-icon-size: var(--xh-table-sort-size, var(--xh-_table-trigger-size));
442
+ }
443
+
444
+ /* 勾选方框是嵌在行里的小块:inset 档圆角(身份表登记);展开箭头与列设置那颗是 control 档 */
445
+ [data-scope='table'][data-part='select-all-trigger'],
446
+ [data-scope='table'][data-part='row-select-trigger'] {
447
+ --xh-action-radius: var(--xh-table-trigger-radius, var(--xh-shape-inset));
448
+ }
449
+
450
+ [data-scope='table'][data-part='column-visibility-trigger'],
451
+ [data-scope='table'][data-part='expand-trigger'],
452
+ [data-scope='table'][data-part='sort-trigger'] {
453
+ --xh-action-radius: var(--xh-table-trigger-radius, var(--xh-shape-control));
262
454
  }
263
455
 
264
456
  [data-scope='table'][data-part='select-all-trigger'][hidden],
265
457
  [data-scope='table'][data-part='row-select-trigger'][hidden],
266
- [data-scope='table'][data-part='expand-trigger'][hidden] {
458
+ [data-scope='table'][data-part='column-visibility-trigger'][hidden],
459
+ [data-scope='table'][data-part='expand-trigger'][hidden],
460
+ [data-scope='table'][data-part='sort-trigger'][hidden] {
267
461
  display: none;
268
462
  }
269
463
 
270
- /* 两个选择把手:未选中时只剩一个空框,勾选标记靠 visibility 显隐,
464
+ /* 三个勾选把手:未选中时只剩一个空框(描边画出的透明底空框),勾选标记靠前景色显隐,
271
465
  切换选中不引起行宽抖动 */
272
466
  [data-scope='table'][data-part='select-all-trigger'],
273
- [data-scope='table'][data-part='row-select-trigger'] {
274
- border: var(--xh-stroke-thin) solid var(--xh-table-trigger-border, var(--xh-border-control));
275
- color: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
467
+ [data-scope='table'][data-part='row-select-trigger'],
468
+ [data-scope='table'][data-part='column-visibility-trigger'] {
469
+ --xh-_table-trigger-bg: transparent;
470
+ --xh-_table-trigger-border: var(--xh-table-trigger-border, var(--xh-border-control));
471
+ --xh-_table-trigger-fg: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
472
+ --xh-action-fg-rest: var(--xh-_table-trigger-fg);
473
+ --xh-action-fg-hover: var(--xh-_table-trigger-fg);
474
+ --xh-action-fg-pressed: var(--xh-_table-trigger-fg);
475
+ --xh-action-fg-focus-visible: var(--xh-_table-trigger-fg);
476
+
276
477
  visibility: visible;
277
478
  }
278
479
 
480
+ /* 已勾选的方框是品牌实心面,按下在它之上派生 active 面 */
279
481
  [data-scope='table'][data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate']),
482
+ [data-scope='table'][data-part='column-visibility-trigger'][data-state='checked'],
280
483
  [data-scope='table'][data-part='row-select-trigger'][data-selected] {
281
- border-color: var(--xh-table-trigger-border-checked, var(--xh-table-trigger-bg-checked, var(--xh-bg-brand)));
282
- background: var(--xh-table-trigger-bg-checked, var(--xh-bg-brand));
484
+ --xh-_table-trigger-bg: var(--xh-table-trigger-bg-checked, var(--xh-bg-brand));
485
+ --xh-_table-trigger-bg-pressed: var(--xh-table-trigger-bg-checked-pressed, var(--xh-bg-brand-active));
486
+ --xh-_table-trigger-border: var(--xh-table-trigger-border-checked, var(--xh-table-trigger-bg-checked, var(--xh-bg-brand)));
487
+ }
488
+
489
+ /* 面是实心的,环色与面同族,画在面里就看不出来;环改取面自己的前景色——
490
+ 那一族色本来就要在这块面上把字读清楚,与面的对比是按可读性定的。
491
+ 置灰那档不在其列:底已换成淡底、勾也藏成透明,currentColor 取到的是透明,环整个消失;
492
+ aria-disabled 的把手仍能落焦,环退回默认那一支 */
493
+ [data-scope='table'][data-part='select-all-trigger']:is([data-state='checked'], [data-state='indeterminate']):not([data-disabled]),
494
+ [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]) {
496
+ --xh-action-ring-color-focus-visible: currentColor;
497
+ }
498
+
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));
283
503
  }
284
504
 
285
505
  /* 未选中时勾不出现,但盒子还在:它是边框画出来的空框 */
286
506
  [data-scope='table'][data-part='select-all-trigger'][data-state='unchecked'],
507
+ [data-scope='table'][data-part='column-visibility-trigger'][data-state='unchecked'],
287
508
  [data-scope='table'][data-part='row-select-trigger']:not([data-selected]) {
288
- color: transparent;
509
+ --xh-_table-trigger-fg: transparent;
289
510
  }
290
511
 
291
512
  /* 半选换一枚横杠字形盖住勾:aria-checked=mixed 在视觉上也得与"全选"分得开。
292
513
  横杠与勾同走字形令牌,作者换掉标记时两态一起换 */
293
514
  [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate'] {
294
- position: relative;
295
- color: transparent;
515
+ --xh-_table-trigger-fg: transparent;
296
516
  }
297
517
 
298
518
  [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate']::after {
@@ -305,20 +525,13 @@
305
525
  mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
306
526
  }
307
527
 
528
+ /* 禁用(§7.2 第 9 条):--xh-border-default 描边 + --xh-bg-subtle 底,勾藏起来;家族的禁用块按映射给 */
308
529
  [data-scope='table'][data-part='select-all-trigger'][data-disabled],
530
+ [data-scope='table'][data-part='column-visibility-trigger'][data-disabled],
309
531
  [data-scope='table'][data-part='row-select-trigger'][data-disabled] {
310
- border-color: var(--xh-border-subtle);
311
- background: var(--xh-bg-muted);
312
- color: transparent;
313
- cursor: not-allowed;
314
- }
315
-
316
- /* 全选把手是表头里独立的 Tab 停靠点,环得画在它自己身上。
317
- 往内收,与行、排序把手同一口径:把手长在列头里,列头与根都收 overflow,
318
- 环画在外沿会被裁掉 */
319
- [data-scope='table'][data-part='select-all-trigger']:focus-visible {
320
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
321
- outline-offset: calc(-1 * var(--xh-ring-width));
532
+ --xh-action-border-disabled: var(--xh-border-default);
533
+ --xh-action-bg-disabled: var(--xh-bg-subtle);
534
+ --xh-action-fg-disabled: transparent;
322
535
  }
323
536
 
324
537
  /* 行选择把手不占 Tab 位(键盘那一路走 Space),只服务指针 */
@@ -328,8 +541,18 @@
328
541
 
329
542
  /* 展开箭头:收起时朝向行首、展开时转向下方,与逻辑书写方向一致 */
330
543
  [data-scope='table'][data-part='expand-trigger'] {
331
- color: var(--xh-table-expand-fg, var(--xh-fg-subtle));
332
- transition: rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
544
+ --xh-action-fg-rest: var(--xh-table-expand-fg, var(--xh-fg-subtle));
545
+ --xh-action-fg-hover: var(--xh-table-expand-fg, var(--xh-fg-subtle));
546
+ --xh-action-fg-pressed: var(--xh-table-expand-fg, var(--xh-fg-subtle));
547
+ --xh-action-fg-focus-visible: var(--xh-table-expand-fg, var(--xh-fg-subtle));
548
+ --xh-action-bg-disabled: transparent;
549
+ --xh-action-border-disabled: transparent;
550
+
551
+ /* 这条整份改写家族的过渡列表,按压的 scale 与换底要一起带回来 */
552
+ transition:
553
+ rotate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter-strong),
554
+ background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
555
+ scale var(--xh-motion-duration-release) var(--xh-motion-ease-release);
333
556
  }
334
557
 
335
558
  [data-scope='table'][data-part='expand-trigger'][data-state='open'] {
@@ -346,37 +569,326 @@
346
569
  }
347
570
 
348
571
  [data-scope='table'][data-part='expand-trigger'][data-disabled] {
349
- color: var(--xh-fg-disabled);
350
- cursor: not-allowed;
572
+ --xh-action-fg-disabled: var(--xh-fg-disabled);
351
573
  }
352
574
 
353
575
  [data-scope='table'][data-part='expand-trigger']:focus-visible {
354
576
  outline: none;
355
577
  }
356
578
 
357
- /* 排序把手撑满列标题:整块列标题都点得动,而不是只有那一小截文字 */
579
+ /* 排序钮是列头里独立的定尺图标钮(§9.1):不包列名,列名留在列头上、它排在列名之后,auto 外边距把它
580
+ 推到行尾侧与列宽把手并排。盒型与 0.97 按压由家族 icon 档给(见五颗把手共用块);坐在表头淡底上,
581
+ 悬停 / 按下面按 header 的 host 槽下发的阶梯走(hover 200 → pressed 300),不取白底行那档。
582
+ 箭头静息取 subtle 前景,参与排序的列换成默认前景(见字形块) */
358
583
  [data-scope='table'][data-part='sort-trigger'] {
584
+ --xh-action-bg-hover: var(--xh-table-sort-bg-hover, var(--xh-_action-variant-bg-hover));
585
+ --xh-action-bg-pressed: var(--xh-table-sort-bg-pressed, var(--xh-_action-variant-bg-pressed));
586
+ --xh-action-bg-disabled: transparent;
587
+ --xh-action-border-disabled: transparent;
588
+ --xh-action-fg-rest: var(--xh-table-sort-fg, var(--xh-fg-subtle));
589
+ --xh-action-fg-hover: var(--xh-table-sort-fg, var(--xh-fg-subtle));
590
+ --xh-action-fg-pressed: var(--xh-table-sort-fg, var(--xh-fg-subtle));
591
+ --xh-action-fg-focus-visible: var(--xh-table-sort-fg, var(--xh-fg-subtle));
592
+ --xh-action-fg-disabled: var(--xh-fg-disabled);
593
+
594
+ margin-inline-start: auto;
595
+ }
596
+
597
+ [data-scope='table'][data-part='sort-trigger'][data-sort] {
598
+ --xh-action-fg-rest: var(--xh-table-sort-fg-active, var(--xh-fg-default));
599
+ --xh-action-fg-hover: var(--xh-table-sort-fg-active, var(--xh-fg-default));
600
+ --xh-action-fg-pressed: var(--xh-table-sort-fg-active, var(--xh-fg-default));
601
+ --xh-action-fg-focus-visible: var(--xh-table-sort-fg-active, var(--xh-fg-default));
602
+ }
603
+
604
+ /* 列宽把手贴在表头格的行尾侧。它压在相邻两列的接缝上,因此往外挪半个身位,
605
+ 两边各留出一点可抓的余量——贴着边只有一两个像素能按到。 */
606
+ [data-scope='table'][data-part='column-resize-trigger'] {
359
607
  display: inline-flex;
360
- flex: 1;
608
+ flex: none;
609
+ align-self: stretch;
610
+ inline-size: var(--xh-table-resize-width, var(--xh-space-2));
611
+ /* 推到行尾侧。把手在标记里是表头格的最后一个孩子,auto 外边距把它顶到那一头,
612
+ 不必给每个表头格加定位上下文——那条会落到所有既有表格上 */
613
+ margin-inline-start: auto;
361
614
  align-items: center;
362
- gap: var(--xh-table-sort-gap, var(--xh-space-1));
363
- min-inline-size: 0;
615
+ justify-content: center;
616
+ cursor: col-resize;
617
+ touch-action: none;
618
+ }
619
+
620
+ [data-scope='table'][data-part='column-resize-trigger'][hidden] {
621
+ display: none;
622
+ }
623
+
624
+ /* 同一格里前面已有排序钮时,auto 外边距只归第一颗:两条 auto 会把余量平分,排序钮就被推到格中间;
625
+ 列宽把手紧贴排序钮之后。藏起来的排序钮不占位,也就不该夺走这条边距 */
626
+ [data-scope='table'][data-part='sort-trigger']:not([hidden]) ~ [data-scope='table'][data-part='column-resize-trigger'] {
627
+ margin-inline-start: 0;
628
+ }
629
+
630
+ /* 接缝上那条线。平时借表头的分隔色,按住与聚焦时换成品牌色好认 */
631
+ [data-scope='table'][data-part='column-resize-trigger']::after {
632
+ content: '';
633
+ display: block;
634
+ inline-size: var(--xh-table-resize-line, var(--xh-stroke-thin));
635
+ block-size: var(--xh-table-resize-line-length, 60%);
636
+ border-radius: var(--xh-table-resize-radius, var(--xh-shape-pill));
637
+ background: var(--xh-table-resize-fg, var(--xh-border-default));
638
+ }
639
+
640
+ [data-scope='table'][data-part='column-resize-trigger']:hover::after,
641
+ [data-scope='table'][data-part='column-resize-trigger'][data-resizing]::after {
642
+ background: var(--xh-table-resize-fg-active, var(--xh-bg-brand));
643
+ block-size: 100%;
644
+ }
645
+
646
+ /* 不可改宽的列不显示把手:留着一条抓不动的线只会让人反复去试 */
647
+ [data-scope='table'][data-part='column-resize-trigger'][data-disabled] {
648
+ display: none;
649
+ }
650
+
651
+ /* 列拖拽把手贴在表头格的行首侧,位置由源码顺序定,不写 auto 外边距:
652
+ 同一个表头格里的改宽把手已经用 margin-inline-start: auto 把自己顶到行尾侧,
653
+ 再添一条 auto,剩余空白会在两条外边距之间平分,两个把手谁都到不了自己那一头。
654
+ 待在行首侧还有一层好处:它的位置与这一列有多宽、格里有没有排序把手都无关 */
655
+ [data-scope='table'][data-part='column-drag-trigger'] {
656
+ display: inline-flex;
657
+ flex: none;
658
+ align-items: center;
659
+ justify-content: center;
660
+ inline-size: var(--xh-table-drag-size, var(--xh-control-indicator-size));
661
+ block-size: var(--xh-table-drag-size, var(--xh-control-indicator-size));
364
662
  border-radius: var(--xh-table-trigger-radius, var(--xh-shape-control));
365
- color: inherit;
366
- font: inherit;
367
- text-align: start;
368
- cursor: pointer;
663
+ color: var(--xh-table-drag-fg, var(--xh-fg-subtle));
664
+ cursor: grab;
665
+ /* 关掉这一轴的默认手势:不关的话触屏上手指一划就被系统当成滚动收走 */
666
+ touch-action: none;
369
667
  }
370
668
 
371
- [data-scope='table'][data-part='sort-trigger'][hidden] {
669
+ [data-scope='table'][data-part='column-drag-trigger'][hidden] {
670
+ display: none;
671
+ }
672
+
673
+ /* 抓手是两条竖线:盒子取边框盒,两侧描边就是那两条线,宽高与线宽都走令牌。
674
+ :empty 守卫让作者塞进来的图标整个顶掉它,而不是两份叠在一起 */
675
+ [data-scope='table'][data-part='column-drag-trigger']:empty::after {
676
+ content: '';
677
+ display: block;
678
+ inline-size: var(--xh-table-drag-grip-w, var(--xh-space-1));
679
+ block-size: var(--xh-table-drag-grip-h, var(--xh-space-2));
680
+ border-inline: var(--xh-stroke-thin) solid currentColor;
681
+ }
682
+
683
+ [data-scope='table'][data-part='column-drag-trigger']:not([data-disabled]):hover,
684
+ [data-scope='table'][data-part='column-drag-trigger'][data-dragging] {
685
+ color: var(--xh-table-drag-fg-active, var(--xh-fg-default));
686
+ }
687
+
688
+ [data-scope='table'][data-part='column-drag-trigger'][data-dragging] {
689
+ cursor: grabbing;
690
+ }
691
+
692
+ /* 不可拖的列照样带一个把手,这里保住它的位置、只把它压到禁用色。
693
+ 收成 display: none 是不行的:把手在行首侧,藏掉之后同一行里能拖与不能拖的两列,
694
+ 标题起点会错开一格 */
695
+ [data-scope='table'][data-part='column-drag-trigger'][data-disabled] {
696
+ color: var(--xh-table-drag-fg-disabled, var(--xh-fg-disabled));
697
+ }
698
+
699
+ /* 落点指示线:拖到哪一列的哪一侧,线就画在那一列的那条边上。列头与表体的格子一起画,
700
+ 线贯穿整张表才看得出这一列要落到哪儿。
701
+ 定位上下文由这条规则自己给:列头与格子平时都不定位,缺了它伪元素会一路上溯到表格根,
702
+ 线就飞到整张表的左上角去。
703
+ 冻结列排除在外:它靠 position: sticky 钉住,在这儿改成 relative 会把吸附顶掉;
704
+ 而冻结列既不可拖也不做落点,排除掉不会漏画任何一条线 */
705
+ [data-scope='table'][data-part='column-header'][data-drop]:not([data-frozen]),
706
+ [data-scope='table'][data-part='cell'][data-drop]:not([data-frozen]) {
707
+ position: relative;
708
+ }
709
+
710
+ /* 线整条画在盒内:列头与格子都收 overflow: hidden,压着边画会被裁掉半条 */
711
+ [data-scope='table'][data-part='column-header'][data-drop]:not([data-frozen])::after,
712
+ [data-scope='table'][data-part='cell'][data-drop]:not([data-frozen])::after {
713
+ content: '';
714
+ position: absolute;
715
+ inset-block: 0;
716
+ inline-size: var(--xh-table-drop-line, var(--xh-stroke-thick));
717
+ background: var(--xh-table-drop-fg, var(--xh-bg-brand));
718
+ }
719
+
720
+ /* 落在哪一侧走逻辑属性:rtl 下 before 自己就换到右边去了。
721
+ 换成 box-shadow: inset 的话偏移量是物理的,书写方向一反 before 与 after 就调个个儿 */
722
+ [data-scope='table'][data-part='column-header'][data-drop='before']:not([data-frozen])::after,
723
+ [data-scope='table'][data-part='cell'][data-drop='before']:not([data-frozen])::after {
724
+ inset-inline-start: 0;
725
+ }
726
+
727
+ [data-scope='table'][data-part='column-header'][data-drop='after']:not([data-frozen])::after,
728
+ [data-scope='table'][data-part='cell'][data-drop='after']:not([data-frozen])::after {
729
+ inset-inline-end: 0;
730
+ }
731
+
732
+ /* 被拖的那一列整列压暗,让人看得出正在搬的是它。这里只动 opacity 与 user-select,
733
+ 一个 transform 都不写:冻结列是 position: sticky,祖先一有 transform 就掉出吸附。
734
+ 位置的事全交给落点指示线,被拖的列自己原地不动 */
735
+ [data-scope='table'][data-part='column-header'][data-dragging],
736
+ [data-scope='table'][data-part='cell'][data-dragging] {
737
+ opacity: var(--xh-table-dragging-opacity, var(--xh-state-dragging-opacity));
738
+ user-select: none;
739
+ }
740
+
741
+ /* —— 行拖拽排序 —— */
742
+ /* 整行都是拖动源,光标换成抓手告诉人这一行按得动。
743
+ 这条不写 touch-action:整行关掉纵向手势,表格自己就滚不动了;
744
+ 触屏那一路交给下面那块专属把手 */
745
+ [data-scope='table'][data-part='row'][data-draggable] {
746
+ cursor: grab;
747
+ }
748
+
749
+ /* 行拖拽把手:行里的一小块专属拖动区,按下即拖。触屏靠它起手,
750
+ 代价只是这一小块地方不再跟着表格滚。整行起手那一路原样保留,把手是叠加的第二个入口。
751
+ touch-action 不在这儿写:连接层按「拖不动就不写」把它写进了内联 style,
752
+ 皮肤再写一遍会盖掉那份条件判断,让不可拖的行也白白让出滚动 */
753
+ [data-scope='table'][data-part='row-drag-trigger'] {
754
+ display: inline-flex;
755
+ flex: none;
756
+ /* 行是 align-items: stretch 的 flex 容器,不自己居中就会被拉成整行高 */
757
+ align-self: center;
758
+ align-items: center;
759
+ justify-content: center;
760
+ inline-size: var(--xh-table-row-drag-size, var(--xh-control-indicator-size));
761
+ block-size: var(--xh-table-row-drag-size, var(--xh-control-indicator-size));
762
+ border-radius: var(--xh-table-trigger-radius, var(--xh-shape-control));
763
+ color: var(--xh-table-row-drag-fg, var(--xh-fg-subtle));
764
+ cursor: grab;
765
+ }
766
+
767
+ [data-scope='table'][data-part='row-drag-trigger'][hidden] {
372
768
  display: none;
373
769
  }
374
770
 
375
- /* 排序方向用箭头字形表出来:aria-sort 只报给读屏,视觉侧也得有对应的东西 */
376
- [data-scope='table'][data-part='sort-trigger']::after {
377
- color: var(--xh-table-sort-fg, var(--xh-fg-subtle));
771
+ /* 抓手是两条横线:盒子取边框盒,块向两侧的描边就是那两条线,宽高与线宽都走令牌。
772
+ 线的走向与能拖的方向垂直——行沿块向上下排,画横线;列沿行向左右排,那边画的是竖线。
773
+ 两处都用逻辑属性,书写模式一换,线跟着排列轴自己转过去。
774
+ :empty 守卫让作者塞进来的图标整个顶掉它,而不是两份叠在一起 */
775
+ [data-scope='table'][data-part='row-drag-trigger']:empty::after {
776
+ content: '';
777
+ display: block;
778
+ inline-size: var(--xh-table-row-drag-grip-long, var(--xh-space-2));
779
+ block-size: var(--xh-table-row-drag-grip-short, var(--xh-space-1));
780
+ border-block: var(--xh-stroke-thin) solid currentColor;
781
+ }
782
+
783
+ [data-scope='table'][data-part='row-drag-trigger']:not([data-disabled]):hover,
784
+ [data-scope='table'][data-part='row-drag-trigger'][data-dragging] {
785
+ color: var(--xh-table-row-drag-fg-active, var(--xh-fg-default));
786
+ }
787
+
788
+ [data-scope='table'][data-part='row-drag-trigger'][data-dragging] {
789
+ cursor: grabbing;
790
+ }
791
+
792
+ /* 不可拖的行照样带一个把手,这里保住它的位置、只把它压到禁用色。
793
+ 收成 display: none 是不行的:把手占着行首那一格,藏掉之后同一张表里能拖与不能拖的两行,
794
+ 首列内容的起点会错开一格 */
795
+ [data-scope='table'][data-part='row-drag-trigger'][data-disabled] {
796
+ color: var(--xh-table-row-drag-fg-disabled, var(--xh-fg-disabled));
797
+ }
798
+
799
+ /* 被拖的行整行压暗,与被拖的列同一档透明度。这里只动 opacity、cursor 与 user-select,
800
+ 一个 transform 都不写:斑马纹按 nth-of-type 算、行间线按兄弟选择器算,两者认的都是 DOM 位置,
801
+ 跟手让位会让它们在拖动全程与行错开。位置的事全交给落点指示线 */
802
+ [data-scope='table'][data-part='row'][data-dragging] {
803
+ opacity: var(--xh-table-dragging-opacity, var(--xh-state-dragging-opacity));
804
+ cursor: grabbing;
805
+ user-select: none;
806
+ }
807
+
808
+ /* 详情行与它的数据行是同一块,一起压暗 */
809
+ [data-scope='table'][data-part='expanded-row'][data-dragging] {
810
+ opacity: var(--xh-table-dragging-opacity, var(--xh-state-dragging-opacity));
811
+ }
812
+
813
+ /* 落点指示:插到两行之间画一条横线,落进一行里面画一整圈。两档都靠伪元素画,
814
+ 定位上下文只给带 data-drop 的那一行:缺了它伪元素会一路上溯到表格根,指示飞到整张表的左上角;
815
+ 写到所有行上则是给每一行都多担一份,而落点同一时刻只有一个 */
816
+ [data-scope='table'][data-part='row'][data-drop] {
817
+ position: relative;
818
+ }
819
+
820
+ /* 线贯穿整行宽度,并且要压在单元格之上:行是 flex 容器,横向吸附的格子带着层号,
821
+ 伪元素不抬到它上面就会被盖住。
822
+ 选择器逐值列出前后两档,不写成裸 [data-drop]:换父那一档用的是同一个 ::after,
823
+ 裸写会让它先摊上一条线高的横条,再由下面那块整个改写 */
824
+ [data-scope='table'][data-part='row']:is([data-drop='before'], [data-drop='after'])::after {
825
+ content: '';
826
+ position: absolute;
827
+ z-index: calc(var(--xh-table-sticky-column-layer, 1) + 1);
828
+ inset-inline: 0;
829
+ block-size: var(--xh-table-drop-line, var(--xh-stroke-thick));
830
+ background: var(--xh-table-drop-fg, var(--xh-bg-brand));
831
+ }
832
+
833
+ /* 线整条画在行内,不压着边。压着边画的话,首行那条上沿线会被表格根的圆角与滚动裁掉半条 */
834
+ [data-scope='table'][data-part='row'][data-drop='before']::after {
835
+ inset-block-start: 0;
836
+ }
837
+
838
+ [data-scope='table'][data-part='row'][data-drop='after']::after {
839
+ inset-block-end: 0;
840
+ }
841
+
842
+ /* 落进这一行里面(这一行成为新的父):整行淡底,与上下沿那条横线一眼分得开。
843
+ 底色打在行上而不是伪元素上,横向吸附的格子取的是 background: inherit,跟着一起换色,
844
+ 横向滚过去时冻结列不会留下一块没上色的补丁。
845
+ 祖先写到 root 与 body 两层,是为把特指度抬到 0-8-0:拖动时指针必然停在落点这一行上、
846
+ 悬停恒真,而悬停那条是 0-6-0、选中那条是 0-3-0,少写一层祖先这块淡底就会被那两档盖掉。
847
+ 禁用的行不接换父落点,:not([data-disabled]) 不会漏画任何一处高亮 */
848
+ [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
+ /* 落点不是选中:品牌淡底专属选中(§7.1),落点面取悬停之上一档的中性面 */
850
+ background: var(--xh-table-drop-inside-bg, var(--xh-bg-subtle-hover));
851
+ }
852
+
853
+ /* 换父那一档的描边:与底色分两层画,因为它得压在横向吸附的格子之上——
854
+ 格子带着层号,画在行自己的背景层上会被首尾的冻结列盖掉半圈。
855
+ 零偏移的内投影四边同时着色、不涉及方向,书写模式一换也不用调;
856
+ 整圈画在行内不压着边,与上下沿那条横线同一口径。
857
+ 行上不写 transform:冻结列是 position: sticky,祖先一有 transform 就掉出吸附 */
858
+ [data-scope='table'][data-part='row'][data-drop='inside']::after {
859
+ content: '';
860
+ position: absolute;
861
+ z-index: calc(var(--xh-table-sticky-column-layer, 1) + 1);
862
+ inset: 0;
863
+ box-shadow: inset 0 0 0 var(--xh-table-drop-line, var(--xh-stroke-thick))
864
+ var(--xh-table-drop-fg, var(--xh-bg-brand));
865
+ /* 这一层盖满整行,让它不接指针,落点判定照旧落到行与格子上 */
866
+ pointer-events: none;
867
+ }
868
+
869
+ /* 活动区域只说给读屏听,不占版面。声明与 shared/visually-hidden.ts 逐条同值。 */
870
+ [data-scope='table'][data-part='live-region'] {
871
+ position: absolute;
872
+ inline-size: 1px;
873
+ block-size: 1px;
874
+ padding: 0;
875
+ margin: -1px;
876
+ overflow: hidden;
877
+ clip-path: inset(50%);
878
+ white-space: nowrap;
879
+ border: 0;
880
+ }
881
+
882
+ /* 排序方向用箭头字形表出来:aria-sort 只报给读屏,视觉侧也得有对应的东西。
883
+ 箭头是指示符(§6.5):尺寸读钮自己改接过的 --xh-icon-size(--xh-table-sort-size,缺省与方盒同边长),
884
+ 与同一表头里的勾选框方盒、列拖拽把手同走 --xh-control-indicator-size,按图标档取的 20px 会比
885
+ 16px 的方盒与列头文字都大一圈。:empty 守卫同展开箭头:作者塞了自己的图标就整个顶掉兜底;
886
+ flex: none 是因为 ghost 那圈透明描边仍占位,不钉住的话与盒同边长的箭头会被挤窄一个描边。
887
+ 三态各写一遍尺寸:字形门禁逐条规则查兜底盒有没有按 --xh-icon-size 量 */
888
+ [data-scope='table'][data-part='sort-trigger']:empty::before {
378
889
  content: '';
379
890
  display: inline-block;
891
+ flex: none;
380
892
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
381
893
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
382
894
  vertical-align: var(--xh-glyph-baseline-shift);
@@ -385,52 +897,50 @@
385
897
  mask: var(--xh-glyph-mark-sort) center / contain no-repeat;
386
898
  }
387
899
 
388
- [data-scope='table'][data-part='sort-trigger'][data-sort='asc']::after {
389
- color: var(--xh-table-sort-fg-active, var(--xh-fg-default));
390
- content: '';
391
- display: inline-block;
900
+ [data-scope='table'][data-part='sort-trigger'][data-sort='asc']:empty::before {
392
901
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
393
902
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
394
- vertical-align: var(--xh-glyph-baseline-shift);
395
- background-color: currentColor;
396
903
  -webkit-mask: var(--xh-glyph-mark-sort-asc) center / contain no-repeat;
397
904
  mask: var(--xh-glyph-mark-sort-asc) center / contain no-repeat;
398
905
  }
399
906
 
400
- [data-scope='table'][data-part='sort-trigger'][data-sort='desc']::after {
401
- color: var(--xh-table-sort-fg-active, var(--xh-fg-default));
402
- content: '';
403
- display: inline-block;
907
+ [data-scope='table'][data-part='sort-trigger'][data-sort='desc']:empty::before {
404
908
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
405
909
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
406
- vertical-align: var(--xh-glyph-baseline-shift);
407
- background-color: currentColor;
408
910
  -webkit-mask: var(--xh-glyph-mark-sort-desc) center / contain no-repeat;
409
911
  mask: var(--xh-glyph-mark-sort-desc) center / contain no-repeat;
410
912
  }
411
913
 
412
- /* 多字段排序的优先级角标:链里第几环就显几,只在参与排序时才有 data-sort-index */
413
- [data-scope='table'][data-part='sort-trigger'][data-sort-index]::before {
414
- order: 1;
914
+ /* 多字段排序的优先级角标:链里第几环就显几,只在参与排序时才有 data-sort-index
915
+ 钮是定尺的 16px 方盒,数字排不进盒里:角标压在盒的行尾上角,写法同 Badge 的 top-end——
916
+ 定位上下文由家族给(控件本身 position: relative),inset 走逻辑属性,rtl 下 end 自己换到左边 */
917
+ [data-scope='table'][data-part='sort-trigger'][data-sort-index]::after {
918
+ position: absolute;
919
+ inset-block-start: 0;
920
+ inset-inline-end: 0;
921
+ translate: 50% -50%;
415
922
  color: var(--xh-table-sort-fg-active, var(--xh-fg-default));
416
923
  font-size: var(--xh-text-caption-size);
924
+ line-height: 1;
417
925
  content: attr(data-sort-index);
926
+ pointer-events: none;
927
+ }
928
+
929
+ /* rtl 下 translate 的行内轴要跟着翻,否则角标会往盒里面跑 */
930
+ [dir='rtl'] [data-scope='table'][data-part='sort-trigger'][data-sort-index]::after {
931
+ translate: -50% -50%;
418
932
  }
419
933
 
420
934
  [data-scope='table'][data-part='sort-trigger'][data-disabled] {
421
935
  cursor: default;
422
936
  }
423
937
 
424
- [data-scope='table'][data-part='sort-trigger'][data-disabled]::after {
938
+ /* 排不了序的列不画箭头 */
939
+ [data-scope='table'][data-part='sort-trigger'][data-disabled]:empty::before {
425
940
  content: none;
426
941
  }
427
942
 
428
- [data-scope='table'][data-part='sort-trigger']:focus-visible {
429
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
430
- outline-offset: calc(-1 * var(--xh-ring-width));
431
- }
432
-
433
- /* 详情行:靠 hidden 收起,不卸载作者节点。内容长在它的单元格里,行本身只画底色 */
943
+ /* 详情行:靠 data-state 收起,不卸载作者节点。内容长在它的单元格里,行本身只画底色 */
434
944
  [data-scope='table'][data-part='expanded-row'] {
435
945
  display: flex;
436
946
  align-items: stretch;
@@ -445,14 +955,16 @@
445
955
  white-space: normal;
446
956
  }
447
957
 
448
- /* 收起态的唯一开关:display 会盖掉 hidden 属性的 UA 规则,漏了这条详情行就收不起来 */
449
- [data-scope='table'][data-part='expanded-row'][hidden] {
958
+ /* 收起态的唯一开关:display 会盖掉 hidden 属性的 UA 规则,漏了这条详情行就收不起来。
959
+ 作者写的 hidden 与连接层发的 data-state=closed 都收在这里 */
960
+ [data-scope='table'][data-part='expanded-row'][hidden],
961
+ [data-scope='table'][data-part='expanded-row'][data-state='closed'] {
450
962
  display: none;
451
963
  }
452
964
 
453
965
  /* 两个状态节点常挂,只在表体为空时才显形 */
454
966
  [data-scope='table'][data-part='empty'],
455
- [data-scope='table'][data-part='loading-state'] {
967
+ [data-scope='table'][data-part='loading'] {
456
968
  display: flex;
457
969
  flex-direction: column;
458
970
  align-items: center;
@@ -466,27 +978,55 @@
466
978
  }
467
979
 
468
980
  [data-scope='table'][data-part='empty'][hidden],
469
- [data-scope='table'][data-part='loading-state'][hidden] {
981
+ [data-scope='table'][data-part='loading'][hidden] {
470
982
  display: none;
471
983
  }
472
984
 
473
- [data-scope='table'][data-part='loading-state'] {
474
- animation: xh-table-loading-pulse calc(var(--xh-spin-duration) / 2) var(--xh-ease-standard) infinite alternate;
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;
988
+ }
989
+
990
+ /* 取下一页的按钮:铺满一行摆在表尾——铺满一行的独立动作条目,接 Action Control 的 row 档、
991
+ ghost 形态(§9.2):宽度由容器给、高度随内容、按下只换面不缩放;盒几何、悬停 / 按下 / 禁用面、
992
+ 焦点环与粗指针热区全由家族给,白底承载 hover 100 → pressed 200。
993
+ 这里只把使用者槽映射到桥接槽并把文案居中:它是一行里唯一的东西,靠起始缘会像一条没对齐的行 */
994
+ [data-scope='table'][data-part='load-more-trigger'] {
995
+ --xh-action-gap: var(--xh-table-load-more-trigger-gap, var(--xh-space-2));
996
+ --xh-action-padding-block: var(--xh-table-load-more-trigger-py, var(--xh-space-3));
997
+ --xh-action-padding-inline: var(--xh-table-load-more-trigger-px, var(--xh-space-4));
998
+ --xh-action-radius: var(--xh-table-load-more-trigger-radius, var(--xh-shape-control));
999
+ --xh-action-bg-hover: var(--xh-table-load-more-trigger-bg-hover, var(--xh-_action-variant-bg-hover));
1000
+ --xh-action-fg-rest: var(--xh-table-load-more-trigger-fg, var(--xh-fg-brand-strong));
1001
+ --xh-action-fg-hover: var(--xh-table-load-more-trigger-fg, var(--xh-fg-brand-strong));
1002
+ --xh-action-fg-pressed: var(--xh-table-load-more-trigger-fg, var(--xh-fg-brand-strong));
1003
+ --xh-action-font-size: var(--xh-table-load-more-trigger-font-size, var(--xh-_table-font-size));
1004
+
1005
+ justify-content: center;
1006
+ text-align: center;
1007
+ /* row 档允许换行、高度随内容,折行的文案走正文行高(§6.4) */
1008
+ line-height: var(--xh-leading-normal);
1009
+ }
1010
+
1011
+ [data-scope='table'][data-part='load-more-trigger'][hidden] {
1012
+ display: none;
475
1013
  }
476
1014
 
477
1015
  /* 减少动效:呼吸停下,加载态只留静止的文案。两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
478
1016
  @media (prefers-reduced-motion: reduce) {
479
- [data-scope='table'][data-part='loading-state'] {
1017
+ [data-scope='table'][data-part='loading'] {
480
1018
  animation: none;
481
1019
  }
482
1020
  }
483
1021
 
484
- :where([data-motion='reduce']) [data-scope='table'][data-part='loading-state'] {
1022
+ :where([data-motion='reduce']) [data-scope='table'][data-part='loading'] {
485
1023
  animation: none;
486
1024
  }
487
1025
 
488
- /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
1026
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中。
1027
+ 尺寸读把手自己改接过的 --xh-icon-size:勾是方盒边长 × 0.75、chevron 与方盒同边长(见把手块) */
489
1028
  [data-scope='table'][data-part='select-all-trigger']:empty::before,
1029
+ [data-scope='table'][data-part='column-visibility-trigger']:empty::before,
490
1030
  [data-scope='table'][data-part='row-select-trigger']:empty::before {
491
1031
  content: '';
492
1032
  display: inline-block;
@@ -498,9 +1038,11 @@
498
1038
  mask: var(--xh-glyph-mark-check) center / contain no-repeat;
499
1039
  }
500
1040
 
1041
+ /* flex: none:方盒是 ghost 形态,家族那圈透明描边仍占位,不钉住的话与盒同边长的 chevron 会被挤窄一个描边 */
501
1042
  [data-scope='table'][data-part='expand-trigger']:empty::before {
502
1043
  content: '';
503
1044
  display: inline-block;
1045
+ flex: none;
504
1046
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
505
1047
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
506
1048
  vertical-align: var(--xh-glyph-baseline-shift);
@@ -508,4 +1050,39 @@
508
1050
  -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
509
1051
  mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
510
1052
  }
1053
+
1054
+ @media print {
1055
+ /* 打印:动画会被定格在任意一帧——转了一半的圈、扫到一半的微光。这里换成静止的表达,
1056
+ 取值与减弱动效那一档相同。两档各写一块、不并进一条媒体查询列表:减弱动效另有一份
1057
+ :where([data-motion='reduce']) 的钩子版本与它成对,打印没有对应的钩子可配,
1058
+ 并成一条之后这层配对关系在文本上就断了。 */
1059
+ [data-scope='table'][data-part='loading'] {
1060
+ animation: none;
1061
+ }
1062
+
1063
+ /* 底色被丢掉:选中行那层淡底没了,与别的行一模一样。改画一条内收的实线框——
1064
+ 用 outline 不用 border:行是横排 flex,加边会把单元格整体往里推,没选中的行不加边,
1065
+ 同一屏上的列就对不齐了 */
1066
+ [data-scope='table'][data-part='row'][data-selected] {
1067
+ outline: var(--xh-stroke-thick) solid currentColor;
1068
+ outline-offset: calc(-1 * var(--xh-stroke-thick));
1069
+ }
1070
+
1071
+ /* 两个勾选框的实心底也被丢掉,配它的浅色勾落在白纸上就整个不见了——
1072
+ 勾与框都换成正文色,勾没勾在纸上才分得出 */
1073
+ [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] {
1075
+ border-color: var(--xh-fg-default);
1076
+ }
1077
+
1078
+ [data-scope='table'][data-part='select-all-trigger'][data-state='checked'],
1079
+ [data-scope='table'][data-part='row-select-trigger'][data-selected] {
1080
+ color: var(--xh-fg-default);
1081
+ }
1082
+
1083
+ /* 半选那枚横杠是伪元素画的,字色照旧留成透明把勾压住,只换横杠自己的颜色 */
1084
+ [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate']::after {
1085
+ background-color: var(--xh-fg-default);
1086
+ }
1087
+ }
511
1088
  }