@xihan-ui/styles 1.1.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 +4954 -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 +143 -19
  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 +123 -28
  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 +429 -143
  123. package/css/tabs.css +475 -52
  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 +172 -69
  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 -128
  157. package/index.unlayered.css +33305 -17727
  158. package/package.json +49 -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
- }
151
-
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));
156
- }
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);
157
263
 
158
- /* 选中比高亮更"实":它表达的是数据状态,翻页回来还在 */
159
- [data-scope='table'][data-part='row'][data-selected] {
160
- background: var(--xh-table-row-bg-selected, var(--xh-bg-subtle-active));
264
+ transition: none;
161
265
  }
162
266
 
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 */
@@ -231,18 +343,27 @@
231
343
  只靠排在基础底之后压过它一条。照字面写祖先链是 0-8-0,比悬停与选中都高,
232
344
  斑马表里偶数行会既不响应悬停也显不出选中 */
233
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)) {
234
- background: var(--xh-table-row-bg-striped, var(--xh-bg-subtle));
346
+ /* 改的是家族的 rest 槽而不是 background 本身:悬停、选中、按下各态由家族在同一支私有槽上解算,
347
+ 直接写 background 会把它们全压掉 */
348
+ --xh-collection-bg-rest: var(--xh-table-row-bg-striped, var(--xh-bg-subtle));
235
349
  }
236
350
 
237
- /* 无外框:只留行间横线,圆角也随之无意义 */
238
- [data-scope='table'][data-part='root'][data-borderless] {
239
- border: 0;
240
- border-radius: 0;
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));
356
+ }
357
+
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));
241
362
  }
242
363
 
243
364
  /* 竖分隔线:列与列之间一道细线,末列不画 */
244
- [data-scope='table'][data-part='root'][data-ruled] [data-scope='table'][data-part='column-header']:not(:last-child),
245
- [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) {
246
367
  border-inline-end: var(--xh-stroke-thin) solid var(--xh-table-row-border, var(--xh-border-subtle));
247
368
  }
248
369
 
@@ -250,52 +371,148 @@
250
371
  color: var(--xh-fg-disabled);
251
372
  }
252
373
 
253
- /* 三个把手共用一副方形盒子,两种行的文字起点才对得齐 */
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 */
254
429
  [data-scope='table'][data-part='select-all-trigger'],
255
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
+
256
435
  [data-scope='table'][data-part='expand-trigger'] {
257
- display: inline-flex;
258
- flex: none;
259
- align-items: center;
260
- justify-content: center;
261
- inline-size: var(--xh-table-trigger-size, var(--xh-control-indicator-size));
262
- block-size: var(--xh-table-trigger-size, var(--xh-control-indicator-size));
263
- border-radius: var(--xh-table-trigger-radius, var(--xh-shape-control));
264
- 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));
265
454
  }
266
455
 
267
456
  [data-scope='table'][data-part='select-all-trigger'][hidden],
268
457
  [data-scope='table'][data-part='row-select-trigger'][hidden],
269
- [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] {
270
461
  display: none;
271
462
  }
272
463
 
273
- /* 两个选择把手:未选中时只剩一个空框,勾选标记靠 visibility 显隐,
464
+ /* 三个勾选把手:未选中时只剩一个空框(描边画出的透明底空框),勾选标记靠前景色显隐,
274
465
  切换选中不引起行宽抖动 */
275
466
  [data-scope='table'][data-part='select-all-trigger'],
276
- [data-scope='table'][data-part='row-select-trigger'] {
277
- border: var(--xh-stroke-thin) solid var(--xh-table-trigger-border, var(--xh-border-control));
278
- 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
+
279
477
  visibility: visible;
280
478
  }
281
479
 
480
+ /* 已勾选的方框是品牌实心面,按下在它之上派生 active 面 */
282
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'],
283
483
  [data-scope='table'][data-part='row-select-trigger'][data-selected] {
284
- border-color: var(--xh-table-trigger-border-checked, var(--xh-table-trigger-bg-checked, var(--xh-bg-brand)));
285
- 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));
286
503
  }
287
504
 
288
505
  /* 未选中时勾不出现,但盒子还在:它是边框画出来的空框 */
289
506
  [data-scope='table'][data-part='select-all-trigger'][data-state='unchecked'],
507
+ [data-scope='table'][data-part='column-visibility-trigger'][data-state='unchecked'],
290
508
  [data-scope='table'][data-part='row-select-trigger']:not([data-selected]) {
291
- color: transparent;
509
+ --xh-_table-trigger-fg: transparent;
292
510
  }
293
511
 
294
512
  /* 半选换一枚横杠字形盖住勾:aria-checked=mixed 在视觉上也得与"全选"分得开。
295
513
  横杠与勾同走字形令牌,作者换掉标记时两态一起换 */
296
514
  [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate'] {
297
- position: relative;
298
- color: transparent;
515
+ --xh-_table-trigger-fg: transparent;
299
516
  }
300
517
 
301
518
  [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate']::after {
@@ -308,20 +525,13 @@
308
525
  mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
309
526
  }
310
527
 
528
+ /* 禁用(§7.2 第 9 条):--xh-border-default 描边 + --xh-bg-subtle 底,勾藏起来;家族的禁用块按映射给 */
311
529
  [data-scope='table'][data-part='select-all-trigger'][data-disabled],
530
+ [data-scope='table'][data-part='column-visibility-trigger'][data-disabled],
312
531
  [data-scope='table'][data-part='row-select-trigger'][data-disabled] {
313
- border-color: var(--xh-border-subtle);
314
- background: var(--xh-bg-muted);
315
- color: transparent;
316
- cursor: not-allowed;
317
- }
318
-
319
- /* 全选把手是表头里独立的 Tab 停靠点,环得画在它自己身上。
320
- 往内收,与行、排序把手同一口径:把手长在列头里,列头与根都收 overflow,
321
- 环画在外沿会被裁掉 */
322
- [data-scope='table'][data-part='select-all-trigger']:focus-visible {
323
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
324
- 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;
325
535
  }
326
536
 
327
537
  /* 行选择把手不占 Tab 位(键盘那一路走 Space),只服务指针 */
@@ -331,8 +541,18 @@
331
541
 
332
542
  /* 展开箭头:收起时朝向行首、展开时转向下方,与逻辑书写方向一致 */
333
543
  [data-scope='table'][data-part='expand-trigger'] {
334
- color: var(--xh-table-expand-fg, var(--xh-fg-subtle));
335
- 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);
336
556
  }
337
557
 
338
558
  [data-scope='table'][data-part='expand-trigger'][data-state='open'] {
@@ -349,30 +569,36 @@
349
569
  }
350
570
 
351
571
  [data-scope='table'][data-part='expand-trigger'][data-disabled] {
352
- color: var(--xh-fg-disabled);
353
- cursor: not-allowed;
572
+ --xh-action-fg-disabled: var(--xh-fg-disabled);
354
573
  }
355
574
 
356
575
  [data-scope='table'][data-part='expand-trigger']:focus-visible {
357
576
  outline: none;
358
577
  }
359
578
 
360
- /* 排序把手撑满列标题:整块列标题都点得动,而不是只有那一小截文字 */
579
+ /* 排序钮是列头里独立的定尺图标钮(§9.1):不包列名,列名留在列头上、它排在列名之后,auto 外边距把它
580
+ 推到行尾侧与列宽把手并排。盒型与 0.97 按压由家族 icon 档给(见五颗把手共用块);坐在表头淡底上,
581
+ 悬停 / 按下面按 header 的 host 槽下发的阶梯走(hover 200 → pressed 300),不取白底行那档。
582
+ 箭头静息取 subtle 前景,参与排序的列换成默认前景(见字形块) */
361
583
  [data-scope='table'][data-part='sort-trigger'] {
362
- display: inline-flex;
363
- flex: 1;
364
- align-items: center;
365
- gap: var(--xh-table-sort-gap, var(--xh-space-1));
366
- min-inline-size: 0;
367
- border-radius: var(--xh-table-trigger-radius, var(--xh-shape-control));
368
- color: inherit;
369
- font: inherit;
370
- text-align: start;
371
- cursor: pointer;
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;
372
595
  }
373
596
 
374
- [data-scope='table'][data-part='sort-trigger'][hidden] {
375
- display: none;
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));
376
602
  }
377
603
 
378
604
  /* 列宽把手贴在表头格的行尾侧。它压在相邻两列的接缝上,因此往外挪半个身位,
@@ -395,6 +621,12 @@
395
621
  display: none;
396
622
  }
397
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
+
398
630
  /* 接缝上那条线。平时借表头的分隔色,按住与聚焦时换成品牌色好认 */
399
631
  [data-scope='table'][data-part='column-resize-trigger']::after {
400
632
  content: '';
@@ -407,15 +639,10 @@
407
639
 
408
640
  [data-scope='table'][data-part='column-resize-trigger']:hover::after,
409
641
  [data-scope='table'][data-part='column-resize-trigger'][data-resizing]::after {
410
- background: var(--xh-table-resize-fg-active, var(--xh-border-control-focus));
642
+ background: var(--xh-table-resize-fg-active, var(--xh-bg-brand));
411
643
  block-size: 100%;
412
644
  }
413
645
 
414
- [data-scope='table'][data-part='column-resize-trigger']:focus-visible {
415
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
416
- outline-offset: var(--xh-ring-offset);
417
- }
418
-
419
646
  /* 不可改宽的列不显示把手:留着一条抓不动的线只会让人反复去试 */
420
647
  [data-scope='table'][data-part='column-resize-trigger'][data-disabled] {
421
648
  display: none;
@@ -467,12 +694,6 @@
467
694
  标题起点会错开一格 */
468
695
  [data-scope='table'][data-part='column-drag-trigger'][data-disabled] {
469
696
  color: var(--xh-table-drag-fg-disabled, var(--xh-fg-disabled));
470
- cursor: not-allowed;
471
- }
472
-
473
- [data-scope='table'][data-part='column-drag-trigger']:focus-visible {
474
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
475
- outline-offset: var(--xh-ring-offset);
476
697
  }
477
698
 
478
699
  /* 落点指示线:拖到哪一列的哪一侧,线就画在那一列的那条边上。列头与表体的格子一起画,
@@ -493,7 +714,7 @@
493
714
  position: absolute;
494
715
  inset-block: 0;
495
716
  inline-size: var(--xh-table-drop-line, var(--xh-stroke-thick));
496
- background: var(--xh-table-drop-fg, var(--xh-border-control-focus));
717
+ background: var(--xh-table-drop-fg, var(--xh-bg-brand));
497
718
  }
498
719
 
499
720
  /* 落在哪一侧走逻辑属性:rtl 下 before 自己就换到右边去了。
@@ -521,7 +742,7 @@
521
742
  /* 整行都是拖动源,光标换成抓手告诉人这一行按得动。
522
743
  这条不写 touch-action:整行关掉纵向手势,表格自己就滚不动了;
523
744
  触屏那一路交给下面那块专属把手 */
524
- [data-scope='table'][data-part='row'][data-row-draggable] {
745
+ [data-scope='table'][data-part='row'][data-draggable] {
525
746
  cursor: grab;
526
747
  }
527
748
 
@@ -573,12 +794,6 @@
573
794
  首列内容的起点会错开一格 */
574
795
  [data-scope='table'][data-part='row-drag-trigger'][data-disabled] {
575
796
  color: var(--xh-table-row-drag-fg-disabled, var(--xh-fg-disabled));
576
- cursor: not-allowed;
577
- }
578
-
579
- [data-scope='table'][data-part='row-drag-trigger']:focus-visible {
580
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
581
- outline-offset: var(--xh-ring-offset);
582
797
  }
583
798
 
584
799
  /* 被拖的行整行压暗,与被拖的列同一档透明度。这里只动 opacity、cursor 与 user-select,
@@ -612,7 +827,7 @@
612
827
  z-index: calc(var(--xh-table-sticky-column-layer, 1) + 1);
613
828
  inset-inline: 0;
614
829
  block-size: var(--xh-table-drop-line, var(--xh-stroke-thick));
615
- background: var(--xh-table-drop-fg, var(--xh-border-control-focus));
830
+ background: var(--xh-table-drop-fg, var(--xh-bg-brand));
616
831
  }
617
832
 
618
833
  /* 线整条画在行内,不压着边。压着边画的话,首行那条上沿线会被表格根的圆角与滚动裁掉半条 */
@@ -631,7 +846,8 @@
631
846
  悬停恒真,而悬停那条是 0-6-0、选中那条是 0-3-0,少写一层祖先这块淡底就会被那两档盖掉。
632
847
  禁用的行不接换父落点,:not([data-disabled]) 不会漏画任何一处高亮 */
633
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]) {
634
- background: var(--xh-table-drop-inside-bg, var(--xh-bg-brand-subtle));
849
+ /* 落点不是选中:品牌淡底专属选中(§7.1),落点面取悬停之上一档的中性面 */
850
+ background: var(--xh-table-drop-inside-bg, var(--xh-bg-subtle-hover));
635
851
  }
636
852
 
637
853
  /* 换父那一档的描边:与底色分两层画,因为它得压在横向吸附的格子之上——
@@ -645,7 +861,7 @@
645
861
  z-index: calc(var(--xh-table-sticky-column-layer, 1) + 1);
646
862
  inset: 0;
647
863
  box-shadow: inset 0 0 0 var(--xh-table-drop-line, var(--xh-stroke-thick))
648
- var(--xh-table-drop-fg, var(--xh-border-control-focus));
864
+ var(--xh-table-drop-fg, var(--xh-bg-brand));
649
865
  /* 这一层盖满整行,让它不接指针,落点判定照旧落到行与格子上 */
650
866
  pointer-events: none;
651
867
  }
@@ -663,11 +879,16 @@
663
879
  border: 0;
664
880
  }
665
881
 
666
- /* 排序方向用箭头字形表出来:aria-sort 只报给读屏,视觉侧也得有对应的东西 */
667
- [data-scope='table'][data-part='sort-trigger']::after {
668
- color: var(--xh-table-sort-fg, var(--xh-fg-subtle));
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 {
669
889
  content: '';
670
890
  display: inline-block;
891
+ flex: none;
671
892
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
672
893
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
673
894
  vertical-align: var(--xh-glyph-baseline-shift);
@@ -676,52 +897,50 @@
676
897
  mask: var(--xh-glyph-mark-sort) center / contain no-repeat;
677
898
  }
678
899
 
679
- [data-scope='table'][data-part='sort-trigger'][data-sort='asc']::after {
680
- color: var(--xh-table-sort-fg-active, var(--xh-fg-default));
681
- content: '';
682
- display: inline-block;
900
+ [data-scope='table'][data-part='sort-trigger'][data-sort='asc']:empty::before {
683
901
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
684
902
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
685
- vertical-align: var(--xh-glyph-baseline-shift);
686
- background-color: currentColor;
687
903
  -webkit-mask: var(--xh-glyph-mark-sort-asc) center / contain no-repeat;
688
904
  mask: var(--xh-glyph-mark-sort-asc) center / contain no-repeat;
689
905
  }
690
906
 
691
- [data-scope='table'][data-part='sort-trigger'][data-sort='desc']::after {
692
- color: var(--xh-table-sort-fg-active, var(--xh-fg-default));
693
- content: '';
694
- display: inline-block;
907
+ [data-scope='table'][data-part='sort-trigger'][data-sort='desc']:empty::before {
695
908
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
696
909
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
697
- vertical-align: var(--xh-glyph-baseline-shift);
698
- background-color: currentColor;
699
910
  -webkit-mask: var(--xh-glyph-mark-sort-desc) center / contain no-repeat;
700
911
  mask: var(--xh-glyph-mark-sort-desc) center / contain no-repeat;
701
912
  }
702
913
 
703
- /* 多字段排序的优先级角标:链里第几环就显几,只在参与排序时才有 data-sort-index */
704
- [data-scope='table'][data-part='sort-trigger'][data-sort-index]::before {
705
- 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%;
706
922
  color: var(--xh-table-sort-fg-active, var(--xh-fg-default));
707
923
  font-size: var(--xh-text-caption-size);
924
+ line-height: 1;
708
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%;
709
932
  }
710
933
 
711
934
  [data-scope='table'][data-part='sort-trigger'][data-disabled] {
712
935
  cursor: default;
713
936
  }
714
937
 
715
- [data-scope='table'][data-part='sort-trigger'][data-disabled]::after {
938
+ /* 排不了序的列不画箭头 */
939
+ [data-scope='table'][data-part='sort-trigger'][data-disabled]:empty::before {
716
940
  content: none;
717
941
  }
718
942
 
719
- [data-scope='table'][data-part='sort-trigger']:focus-visible {
720
- outline: var(--xh-ring-width) solid var(--xh-ring-focus);
721
- outline-offset: calc(-1 * var(--xh-ring-width));
722
- }
723
-
724
- /* 详情行:靠 hidden 收起,不卸载作者节点。内容长在它的单元格里,行本身只画底色 */
943
+ /* 详情行:靠 data-state 收起,不卸载作者节点。内容长在它的单元格里,行本身只画底色 */
725
944
  [data-scope='table'][data-part='expanded-row'] {
726
945
  display: flex;
727
946
  align-items: stretch;
@@ -736,14 +955,16 @@
736
955
  white-space: normal;
737
956
  }
738
957
 
739
- /* 收起态的唯一开关:display 会盖掉 hidden 属性的 UA 规则,漏了这条详情行就收不起来 */
740
- [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'] {
741
962
  display: none;
742
963
  }
743
964
 
744
965
  /* 两个状态节点常挂,只在表体为空时才显形 */
745
966
  [data-scope='table'][data-part='empty'],
746
- [data-scope='table'][data-part='loading-state'] {
967
+ [data-scope='table'][data-part='loading'] {
747
968
  display: flex;
748
969
  flex-direction: column;
749
970
  align-items: center;
@@ -757,27 +978,55 @@
757
978
  }
758
979
 
759
980
  [data-scope='table'][data-part='empty'][hidden],
760
- [data-scope='table'][data-part='loading-state'][hidden] {
981
+ [data-scope='table'][data-part='loading'][hidden] {
761
982
  display: none;
762
983
  }
763
984
 
764
- [data-scope='table'][data-part='loading-state'] {
765
- 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;
766
1013
  }
767
1014
 
768
1015
  /* 减少动效:呼吸停下,加载态只留静止的文案。两条规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
769
1016
  @media (prefers-reduced-motion: reduce) {
770
- [data-scope='table'][data-part='loading-state'] {
1017
+ [data-scope='table'][data-part='loading'] {
771
1018
  animation: none;
772
1019
  }
773
1020
  }
774
1021
 
775
- :where([data-motion='reduce']) [data-scope='table'][data-part='loading-state'] {
1022
+ :where([data-motion='reduce']) [data-scope='table'][data-part='loading'] {
776
1023
  animation: none;
777
1024
  }
778
1025
 
779
- /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
1026
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中。
1027
+ 尺寸读把手自己改接过的 --xh-icon-size:勾是方盒边长 × 0.75、chevron 与方盒同边长(见把手块) */
780
1028
  [data-scope='table'][data-part='select-all-trigger']:empty::before,
1029
+ [data-scope='table'][data-part='column-visibility-trigger']:empty::before,
781
1030
  [data-scope='table'][data-part='row-select-trigger']:empty::before {
782
1031
  content: '';
783
1032
  display: inline-block;
@@ -789,9 +1038,11 @@
789
1038
  mask: var(--xh-glyph-mark-check) center / contain no-repeat;
790
1039
  }
791
1040
 
1041
+ /* flex: none:方盒是 ghost 形态,家族那圈透明描边仍占位,不钉住的话与盒同边长的 chevron 会被挤窄一个描边 */
792
1042
  [data-scope='table'][data-part='expand-trigger']:empty::before {
793
1043
  content: '';
794
1044
  display: inline-block;
1045
+ flex: none;
795
1046
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
796
1047
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
797
1048
  vertical-align: var(--xh-glyph-baseline-shift);
@@ -799,4 +1050,39 @@
799
1050
  -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
800
1051
  mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
801
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
+ }
802
1088
  }